diff --git a/.ci/AppImageBuilder.yml b/.ci/AppImageBuilder.yml index 08d7be1aee7..61bbcba95e4 100644 --- a/.ci/AppImageBuilder.yml +++ b/.ci/AppImageBuilder.yml @@ -46,11 +46,6 @@ AppDir: - libedit2 # if (CLI:BOOL=ON|QT:BOOL=OFF) - libevdev2 # if QT:BOOL=ON - libfreetype6 - - libgbm1 # if QT:BOOL=ON - - libgl1 # if QT:BOOL=ON - - libgles2 # if QT:BOOL=ON - - libglvnd0 # if QT:BOOL=ON - - libglx0 # if QT:BOOL=ON - libgomp1 - libgs9 - libpng16-16 diff --git a/.ci/Jenkinsfile b/.ci/Jenkinsfile index 94070569e3d..cc3e415cd43 100644 --- a/.ci/Jenkinsfile +++ b/.ci/Jenkinsfile @@ -281,16 +281,12 @@ pipeline { dir(dynarecNames[dynarec]) { dir("$os - $archName") { ret = runBuild("-b \"$packageName\" \"$arch\" ${presetFlags[preset]} ${dynarecFlags[dynarec]} ${osFlags[os]} $buildFlags") - if (presets.size() == 1) - writeFile file: '.forcedir', text: '' } - if ((osArchs.size() == 1) && (thisOsArchs.size() == 1)) - writeFile file: '.forcedir', text: '' } if (ret == 0) { /* Archive resulting artifacts. */ - archiveArtifacts artifacts: "**/$packageName*, **/.forcedir", defaultExcludes: false + archiveArtifacts artifacts: "**/$packageName*", defaultExcludes: false } else { /* Fail this stage. */ failStage() diff --git a/.ci/build.sh b/.ci/build.sh index fb360b826bf..a5b20f2aa63 100755 --- a/.ci/build.sh +++ b/.ci/build.sh @@ -880,6 +880,31 @@ then exit 5 fi +# Download assets if we're making a release build. +if grep -qiE "^BUILD_TYPE:[^=]+=release" build/CMakeCache.txt 2> /dev/null +then + git_repo=$(git remote get-url origin 2> /dev/null) + if [ "$CI" = "true" ] + then + # Backup strategy when running under Jenkins. + [ -z "$git_repo" ] && git_repo=$GIT_URL + fi + if [ -n "$git_repo" ] + then + echo [-] Downloading assets + cd archive_tmp + if ! git clone --depth 1 "$(dirname "$git_repo")/assets.git" assets + then + echo [!] Assets download failed + exit 7 + fi + # Remove dot directories (including .git) and top level files. + rm -rf assets/.* 2> /dev/null + rm -f assets/* 2> /dev/null + cd .. + fi +fi + # Archive the executable and its dependencies. # The executable should always be archived last for the check after this block. status=0 @@ -902,7 +927,7 @@ then [ ! -e "archive_tmp/discord_game_sdk.dll" ] && echo [!] No Discord Game SDK for architecture [$arch_discord] # Archive XAudio2 DLL if required. - grep -q "OPENAL:BOOL=ON" build/CMakeCache.txt || cp -p "/home/$project/dll$arch/xaudio2"* archive_tmp/ + grep -qiE "^OPENAL:BOOL=ON" build/CMakeCache.txt || cp -p "/home/$project/dll$arch/xaudio2"* archive_tmp/ # Archive executable, while also stripping it if requested. if [ $strip -ne 0 ] @@ -971,6 +996,14 @@ then done fi + # Archive assets. + if [ -d archive_tmp/assets ] + then + data_dir="$(echo "archive_tmp/"*".app/Contents")" + mkdir -p "$data_dir/Resources" + mv archive_tmp/assets "$data_dir/Resources/assets" + fi + # Sign app bundle, unless we're in an universal build. [ $skip_archive -eq 0 ] && codesign --force --deep $(mac_signidentity) -o runtime --entitlements src/mac/entitlements.plist --timestamp "archive_tmp/"*".app" elif [ "$BUILD_TAG" = "precondition" ] @@ -982,7 +1015,7 @@ else cwd_root="$(pwd)" check_buildtag "libs.$arch_deb" - if grep -q "OPENAL:BOOL=ON" build/CMakeCache.txt + if grep -qiE "^OPENAL:BOOL=ON" build/CMakeCache.txt then # Build openal-soft 1.23.1 manually to fix audio issues. This is a temporary # workaround until a newer version of openal-soft trickles down to Debian repos. @@ -1133,6 +1166,14 @@ else done project_icon=$(find "$icon_base/"[0-9]*x[0-9]*/* -type f -name '*.png' -o -name '*.svg' | head -1 | grep -oP '/\K([^/]+)(?=\.[^\.]+$)') + # Archive assets. + if [ -d archive_tmp/assets ] + then + data_dir="archive_tmp/usr/local/share/$project" + mkdir -p "$data_dir" + mv archive_tmp/assets "$data_dir/assets" + fi + # Archive executable, while also stripping it if requested. mkdir -p archive_tmp/usr/local/bin if [ $strip -ne 0 ] diff --git a/.github/workflows/cmake_macos.yml b/.github/workflows/cmake_macos.yml index ace5314c89e..f1e0703814b 100644 --- a/.github/workflows/cmake_macos.yml +++ b/.github/workflows/cmake_macos.yml @@ -65,7 +65,7 @@ jobs: - arch: x86_64 toolchain: ./cmake/flags-gcc-x86_64.cmake slug: -x86_64 - runner: macos-13 + runner: macos-15-intel - arch: arm64 toolchain: ./cmake/llvm-macos-aarch64.cmake slug: -arm64 diff --git a/.github/workflows/codeql_macos.yml b/.github/workflows/codeql_macos.yml index 74365cd5658..e3110570922 100644 --- a/.github/workflows/codeql_macos.yml +++ b/.github/workflows/codeql_macos.yml @@ -79,7 +79,7 @@ jobs: - arch: x86_64 toolchain: ./cmake/flags-gcc-x86_64.cmake slug: -x86_64 - runner: macos-13 + runner: macos-15-intel # - arch: arm64 # toolchain: ./cmake/llvm-macos-aarch64.cmake # slug: -arm64 diff --git a/CMakeLists.txt b/CMakeLists.txt index 3004b37117d..667df522148 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,7 @@ if(MUNT_EXTERNAL) endif() project(86Box - VERSION 6.0 + VERSION 5.4 DESCRIPTION "Emulator of x86-based systems" HOMEPAGE_URL "https://86box.net" LANGUAGES C CXX) @@ -184,7 +184,6 @@ cmake_dependent_option(PCL "Generic PCL5e Printer" cmake_dependent_option(SIO_DETECT "Super I/O Detection Helper" ON "DEV_BRANCH" OFF) cmake_dependent_option(WACOM "Wacom Input Devices" ON "DEV_BRANCH" OFF) cmake_dependent_option(XL24 "ATI VGA Wonder XL24 (ATI-28800-6)" ON "DEV_BRANCH" OFF) -cmake_dependent_option(NETSWITCH "Network Switch Support" ON "DEV_BRANCH" OFF) cmake_dependent_option(VFIO "Virtual Function I/O" ON "DEV_BRANCH" OFF) cmake_dependent_option(SOFTMODEM "AC'97 Softmodem" ON "DEV_BRANCH" OFF) @@ -224,7 +223,7 @@ if(NOT EMU_BUILD_NUM) set(EMU_BUILD_NUM 0) endif() if(NOT EMU_COPYRIGHT_YEAR) - set(EMU_COPYRIGHT_YEAR 2025) + set(EMU_COPYRIGHT_YEAR 2026) endif() # Libasan diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000000..e0aaf14104a --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,30 @@ +# Code of Conduct +In order for everyone to enjoy their time contributing to 86Box or otherwise being a part of the community, we kindly ask you to review and follow the below rules. + +## 1. No illegal activity or GitHub ToS violations +- 1.1. Do not distribute malware for non-research purposes. Post samples in a clearly named encrypted archive. +- 1.2. Posting old software is allowed if at least 10 years old and out of support. +- 1.3. Do not post NSFW content (defined at the staff's discretion). +- 1.4. Do not do anything forbidden by the law or the Discord or GitHub Terms of Service. + +## 2. No offensive or disruptive behavior or harassment +- 2.1. No gate-keeping. We aim to accommodate and welcome people of all different opinions and knowledge levels to this community. +- 2.2. You may speak any language but provide a summary in English so that we can understand what you are saying and use English when requested. +- 2.3. Do not retroactively delete messages or do major edits unless you posted something by mistake. +- 2.4. Do not antagonize, defame, demean, blackmail, impersonate, dox others, bring outside drama, use intentionally offensive profile aspects, or otherwise post messages to start a fight (eg. platform wars). Discuss or debate the idea, not the person. +- 2.5. Do not backseat moderate, spam, flood, unsolicitedly ping people, advertise without permission, or evade blocks. +- 2.6. Do not speak on behalf of the project unless you are a team member. This includes all messages which could reasonably be understood as being an official position. Ask a team member if you're unsure about your message. +- 2.7. Decisions by higher-ranked users supersede those by lower-ranked users. This applies to moderation **and** emulator development. Rank and seniority must be earned. +- 2.8. Do not engage in political discussions. +- 2.9. Ignoring essential communication from team members does not exempt you from possible actions against you. Seniority must be earned. + +## 3. Moderation and appeal protocol +- 3.1. Rule violations are punished at the team's discretion, taking all circumstances into account. +- 3.2. Rules enforcement must be equal, impartial, and not retroactive or politically motivated. +- 3.3. Everyone is innocent until proven guilty. +- 3.4. Unless there is an emergency, urgent action is otherwise warranted, or a user is participating with the express purpose of violating our rules, the team shall deliberate before taking action in order to reach consensus and avoid team conflicts. + +## 4. Do not insist on requests or suggestions +- 4.1. You may politely request something from us; if rejected, you are going to be told why and what to do to have it reconsidered. +- 4.2. Follow the contribution requirements listed on the GitHub readme. +- 4.3. Follow proper procedure (eg. for pull requests or bug reports). diff --git a/README.md b/README.md index 506eba7948e..4a248782934 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,10 @@ ===== [![Build Status](https://ci.86box.net/job/86Box/badge/icon)](https://ci.86box.net/job/86Box/) -[![License](https://img.shields.io/github/license/86Box/86Box)](COPYING) [![Latest release](https://img.shields.io/github/release/86Box/86Box.svg)](https://github.com/86Box/86Box/releases) [![Downloads](https://img.shields.io/github/downloads/86Box/86Box/total.svg)](https://github.com/86Box/86Box/releases) +[![License](https://img.shields.io/github/license/86Box/86Box)](COPYING) +[![Latest release](https://img.shields.io/github/release/86Box/86Box.svg)](https://github.com/86Box/86Box/releases) +[![Downloads](https://img.shields.io/github/downloads/86Box/86Box/total.svg)](https://github.com/86Box/86Box/releases) +[![Translation status](https://weblate.86box.net/widget/86box/86box/language-badge.svg)](https://weblate.86box.net/engage/86box/) **86Box** is a low level x86 emulator that runs older operating systems and software designed for IBM PC systems and compatibles from 1981 through fairly recent system designs based on the PCI bus. @@ -53,6 +56,14 @@ We operate an IRC channel and a Discord server for discussing 86Box, its develop [![Visit our Discord server](https://discordapp.com/api/guilds/262614059009048590/embed.png)](https://discord.gg/QXK9XTv) +[Forum: SoftHistory](https://forum.softhistory.org/) + +[Wiki: SoftHistory](https://wiki.softhistory.org/) + +[Twitter: @86BoxEmulator](https://twitter.com/86BoxEmulator) + +[YouTube: 86Box](https://youtube.com/c/86Box) + Contributions ------------- @@ -74,6 +85,5 @@ Donations We do not charge you for the emulator but donations are still welcome: . - You can also support the project on Patreon: . diff --git a/debian/changelog b/debian/changelog index d2606a616a2..c0c4bf945ed 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,5 @@ -86box (6.0) UNRELEASED; urgency=medium +86box (5.4) UNRELEASED; urgency=medium * Bump release. - -- Jasmine Iwanek Sun, 26 Oct 2025 17:41:47 +0100 + -- Jasmine Iwanek Tue, 23 Dec 2025 00:27:45 +0100 diff --git a/src/86box.c b/src/86box.c index 020cb609022..ce9a3d96ea1 100644 --- a/src/86box.c +++ b/src/86box.c @@ -83,6 +83,7 @@ #include <86box/fdc.h> #include <86box/fdc_ext.h> #include <86box/hdd.h> +#include <86box/hdd_audio.h> #include <86box/hdc.h> #include <86box/hdc_ide.h> #include <86box/scsi.h> @@ -271,9 +272,29 @@ struct accelKey def_acc_keys[NUM_ACCELS] = { }, { .name="screenshot", - .desc="Screenshot", + .desc="Take screenshot", .seq="Ctrl+F11" }, + { + .name="raw_screenshot", + .desc="Take raw screenshot", + .seq="" + }, + { + .name="copy_screenshot", + .desc="Copy screenshot", + .seq="" + }, + { + .name="copy_raw_screenshot", + .desc="Copy raw screenshot", + .seq="" + }, + { + .name="fast_forward", + .desc="Fast forward", + .seq="Ctrl+Alt+F" + }, { .name="release_mouse", .desc="Release mouse pointer", @@ -293,6 +314,11 @@ struct accelKey def_acc_keys[NUM_ACCELS] = { .name="mute", .desc="Toggle mute", .seq="Ctrl+Alt+M" + }, + { + .name="force_interpretation", + .desc="Force interpretation", + .seq="Ctrl+Alt+I" } }; @@ -338,8 +364,8 @@ __thread int is_cpu_thread = 0; static wchar_t mouse_msg[3][200]; -static volatile ATOMIC_INT do_pause_ack = 0; -static volatile ATOMIC_INT pause_ack = 0; +static ATOMIC_INT do_pause_ack = 0; +static ATOMIC_INT pause_ack = 0; #define LOG_SIZE_BUFFER 8192 /* Log size buffer */ @@ -762,8 +788,10 @@ pc_init(int argc, char *argv[]) p = path_get_filename(exe_path); *p = '\0'; #if defined(__APPLE__) + char contents_path[2048] = {0}; c = strlen(exe_path); if ((c >= 16) && !strcmp(&exe_path[c - 16], "/Contents/MacOS/")) { + strncpy(contents_path, exe_path, c - 7); exe_path[c - 16] = '\0'; p = path_get_filename(exe_path); *p = '\0'; @@ -1030,10 +1058,27 @@ pc_init(int argc, char *argv[]) path_append_filename(temp, usr_path, "assets"); asset_add_path(temp); - // Add the standard ROM path in the same directory as the executable. + // Add the standard asset path in the same directory as the executable. path_append_filename(temp, exe_path, "assets"); asset_add_path(temp); +#if defined(__APPLE__) + // Add the standard asset path within the app bundle. + if (contents_path[0] != '\0') { + path_append_filename(temp, contents_path, "Resources/assets"); + asset_add_path(temp); + } +#elif !defined(_WIN32) + // Add the standard asset paths within the AppImage. + p = getenv("APPDIR"); + if (p && (p[0] != '\0')) { + path_append_filename(temp, p, "usr/local/share/" EMU_NAME "/assets"); + asset_add_path(temp); + path_append_filename(temp, p, "usr/share/" EMU_NAME "/assets"); + asset_add_path(temp); + } +#endif + plat_init_asset_paths(); /* @@ -1329,7 +1374,7 @@ pc_init_roms(void) while (machine_get_internal_name_ex(c) != NULL) { m = machine_available(c); if (!m) - pclog("Missing machine: %s\n", machine_getname_ex(c)); + pclog("Missing machine: %s\n", machine_getname(c)); c++; } @@ -1370,7 +1415,7 @@ pc_init_modules(void) /* Load the ROMs for the selected machine. */ if (!machine_available(machine)) { - swprintf(temp, sizeof_w(temp), plat_get_string(STRING_HW_NOT_AVAILABLE_MACHINE), machine_getname()); + swprintf(temp, sizeof_w(temp), plat_get_string(STRING_HW_NOT_AVAILABLE_MACHINE), machine_getname(machine)); c = 0; machine = -1; while (machine_get_internal_name_ex(c) != NULL) { @@ -1452,6 +1497,8 @@ pc_init_modules(void) fdd_audio_load_profiles(); fdd_audio_init(); } + + hdd_audio_init(); sound_init(); @@ -1551,12 +1598,22 @@ pc_send_cae(void) extern void softresetx86(void); extern void hardresetx86(void); + extern void biu_set_bus_cycle(int bus_cycle); + extern void biu_set_bus_state(int bus_state); + extern void biu_set_bus_next_state(int bus_next_state); + extern void biu_set_cycle_t1(void); + extern void biu_set_next_cycle(void); + extern int biu_get_bus_cycle(void); + extern int biu_get_bus_state(void); + extern int biu_get_bus_next_state(void); extern void prefetch_queue_set_pos(int pos); extern void prefetch_queue_set_ip(uint16_t ip); - extern void prefetch_queue_set_prefetching(int p); + extern void prefetch_queue_set_in(uint16_t in); + extern void prefetch_queue_set_suspended(int p); extern int prefetch_queue_get_pos(void); extern uint16_t prefetch_queue_get_ip(void); - extern int prefetch_queue_get_prefetching(void); + extern uint16_t prefetch_queue_get_in(void); + extern int prefetch_queue_get_suspended(void); extern int prefetch_queue_get_size(void); */ static void @@ -1695,6 +1752,9 @@ pc_reset_hard_init(void) fdd_reset(); + /* Reset HDD audio to pick up any profile changes */ + hdd_audio_reset(); + /* Reset and reconfigure the SCSI layer. */ scsi_card_init(); @@ -1792,7 +1852,7 @@ update_mouse_msg(void) wchar_t wmachine[2048]; wchar_t *wcp; - mbstowcs(wmachine, machine_getname(), strlen(machine_getname()) + 1); + mbstowcs(wmachine, machine_getname(machine), strlen(machine_getname(machine)) + 1); if (!cpu_override) mbstowcs(wcpufamily, cpu_f->name, strlen(cpu_f->name) + 1); @@ -2114,17 +2174,6 @@ set_screen_size_natural(void) set_screen_size(monitors[i].mon_unscaled_size_x, monitors[i].mon_unscaled_size_y); } -int -get_actual_size_x(void) -{ - return (unscaled_size_x); -} - -int -get_actual_size_y(void) -{ - return (efscrnsz_y); -} void do_pause(int p) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7c389c368a8..4b50879eb71 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -134,6 +134,7 @@ target_link_libraries(86Box scsi sio snd + mdsx_dll utils vid voodoo diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 52ea9797206..e5f6ba259d4 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -3224,6 +3224,22 @@ cdrom_is_empty(const uint8_t id) return ret; } +int +cdrom_is_playing(const uint8_t id) +{ + const cdrom_t *dev = &cdrom[id]; + + return (dev->cd_status == CD_STATUS_PLAYING); +} + +int +cdrom_is_paused(const uint8_t id) +{ + const cdrom_t *dev = &cdrom[id]; + + return (dev->cd_status == CD_STATUS_PAUSED); +} + /* The mechanics of ejecting a CD-ROM from a drive. */ void cdrom_eject(const uint8_t id) diff --git a/src/cdrom/cdrom_image.c b/src/cdrom/cdrom_image.c index 6452868abcf..fdde472515d 100644 --- a/src/cdrom/cdrom_image.c +++ b/src/cdrom/cdrom_image.c @@ -27,12 +27,14 @@ #include #include #include +#include #include #ifndef _WIN32 # include #endif #include <86box/86box.h> #include <86box/log.h> +#include <86box/nvr.h> #include <86box/path.h> #include <86box/plat.h> #include <86box/cdrom.h> @@ -41,11 +43,21 @@ #include +#ifdef ENABLE_IMAGE_LOG +#define LOG_VAR(a) size_t a = +#else +#define LOG_VAR(a) +#endif + +#define NO_CHIPHER_IDS_ENUM +#include "../utils/mds.h" + #define MAX_LINE_LENGTH 512 #define MAX_FILENAME_LENGTH 256 #define CROSS_LEN 512 static char temp_keyword[1024]; +static char temp_file[260] = { 0 }; #define INDEX_SPECIAL -2 /* Track A0h onwards. */ #define INDEX_NONE -1 /* Empty block. */ @@ -138,12 +150,6 @@ typedef enum MODE2_FORM2 = 0xad /* sector size = 2324 (+4) */ } mds_trk_mode_t; -typedef enum -{ - NONE = 0x00, /* no subchannel */ - PW_INTERLEAVED = 0x08 /* 96-byte PW subchannel, interleaved */ -} mds_subch_mode_t; - #pragma pack(push, 1) typedef struct { @@ -175,6 +181,20 @@ typedef struct uint32_t trk_blocks_offs; } mds_sess_block_t; /* 24 bytes */ +/* MDF v2.01 session block. */ +typedef struct +{ + int64_t sess_start; + uint16_t sess_id; + uint8_t all_blocks_num; + uint8_t non_track_blocks_num; + uint16_t first_trk; + uint16_t last_trk; + uint32_t pad; + uint32_t trk_blocks_offs; + int64_t sess_end; +} mds_v2_sess_block_t; /* 24 bytes */ + typedef struct { uint8_t trk_mode; @@ -199,7 +219,13 @@ typedef struct uint64_t start_offs; uint32_t files_num; uint32_t footer_offs; - uint8_t pad1[24]; + union { + uint8_t pad1[24]; + struct { + uint64_t start_sect_v2; + uint8_t pad2[16]; + }; + }; } mds_trk_block_t; /* 80 bytes */ /* @@ -220,6 +246,17 @@ typedef struct uint32_t pad0; } mds_footer_t; /* 16 bytes */ +/* MDF v2.01 track footer block. */ +typedef struct +{ + uint32_t fn_offs; + uint32_t pad; /* Always wide */ + uint32_t pad0; + uint32_t pad1; + uint64_t trk_sectors; + uint64_t pad2; +} mds_v2_footer_t; /* 16 bytes */ + typedef struct { uint32_t type; @@ -1942,6 +1979,191 @@ long int utf16_to_utf8(const uint16_t *u16_str, size_t u16_str_len, return (long int)j; } +int +mds_decrypt_track_data(cd_image_t *img, const char *mdsfile, FILE **fp) +{ + int is_mdx = 0; + + uint64_t mdx_offset = 0ULL; + uint64_t mdx_size_1 = 0ULL; + + if (*fp == NULL) { +#ifdef ENABLE_IMAGE_LOG + log_warning(img->log, " [MDS ] \"%s\" is not open\n", + mdsfile); +#else + warning("\"%s\" is not open\n", mdsfile); +#endif + return 0; + } + + image_log(img->log, "mds_decrypt_track_data(): Decrypting MDS...\n"); + /* + If we are here, them we have already determined in + image_load_mds() that the version is 2.x. + */ + fseek(*fp, 0x2c, SEEK_SET); + + uint64_t offset = 0ULL; + fread(&offset, 1, 4, *fp); + image_log(img->log, "mds_decrypt_track_data(): Offset is %016" PRIX64 "\n", offset); + + if (offset == 0xffffffff) { + image_log(img->log, "mds_decrypt_track_data(): File is MDX\n"); + is_mdx = 1; + + fread(&mdx_offset, 1, 8, *fp); + fread(&mdx_size_1, 1, 8, *fp); + image_log(img->log, "mds_decrypt_track_data(): MDX footer is %" PRIi64 " bytes at offset %016" PRIX64 "\n", mdx_size_1, mdx_offset); + + offset = mdx_offset + (mdx_size_1 - 0x40); + image_log(img->log, "mds_decrypt_track_data(): MDX offset is %016" PRIX64 "\n", offset); + } + + fseek(*fp, offset, SEEK_SET); + + uint8_t data1[0x200]; + + fread(data1, 0x200, 1, *fp); + image_log(img->log, "mds_decrypt_track_data(): Read the first data buffer\n"); + + PCRYPTO_INFO ci; + decode1(data1, NULL, &ci); + image_log(img->log, "data1: %02X %02X %02X %02X\n", data1[0], data1[1], data1[2], data1[3]); + FILE *d1f = fopen("data1.tmp", "wb"); + fwrite(data1, 1, 0x200, d1f); + fclose(d1f); + image_log(img->log, "mds_decrypt_track_data(): Decoded the first data buffer\n"); + + /* Compressed size at 0x150? */ + uint32_t decSize = getU32(data1 + 0x154); /* Decompressed size? */ + image_log(img->log, "mds_decrypt_track_data(): Decompressed size is %i bytes\n", decSize); + + uint64_t data2Offset = 0x30; /* For MDS v2. */ + uint64_t data2Size = offset - 0x30; /* For MDS v2. */ + + if (is_mdx) { + data2Offset = mdx_offset; + data2Size = mdx_size_1 - 0x40; + } + image_log(img->log, "mds_decrypt_track_data(): Second data buffer is %" PRIi64 " bytes at offset %016" PRIX64 "\n", data2Size, data2Offset); + + fseek(*fp, data2Offset, SEEK_SET); + + u8 *data2 = (u8 *)malloc(data2Size); + fread(data2, 1, data2Size, *fp); + image_log(img->log, "mds_decrypt_track_data(): Read the second data buffer\n"); + + DecryptBlock(data2, data2Size, 0, 0, 4, ci); + image_log(img->log, "mds_decrypt_track_data(): Decoded the second data buffer\n"); + + u8 *mdxHeader = (u8 *)malloc(decSize + 0x12); + + z_stream infstream; + infstream.zalloc = Z_NULL; + infstream.zfree = Z_NULL; + infstream.opaque = Z_NULL; + infstream.avail_in = data2Size; + infstream.next_in = data2; + infstream.avail_out = decSize; + infstream.next_out = mdxHeader + 0x12; + + inflateInit(&infstream); + + inflate(&infstream, Z_NO_FLUSH); + inflateEnd(&infstream); + + fseek(*fp, 0, SEEK_SET); + fread(mdxHeader, 1, 0x12, *fp); + + u8 medium_type = getU8(mdxHeader + offsetof(MDX_Header, medium_type)); + int isDVD = 1; + + if (medium_type < 3) // 0, 1, 2 + isDVD = 0; + + Decoder encryptInfo; + encryptInfo.mode = -1; + encryptInfo.ctr = 1; + + u32 keyBlockOff = getU32(mdxHeader + offsetof(MDX_Header, encryption_block_offset)); + + if (keyBlockOff) { + image_log(img->log, "Encryption detected\n"); + + const char *password = NULL; + + image_log(img->log, "Trying without password\n"); + + PCRYPTO_INFO ci2; +#ifdef ENABLE_IMAGE_LOG + if (decode1(mdxHeader + keyBlockOff, password, &ci2) == 0) { + if (password) + image_log(img->log, "Password \"%s\": OK\n", password); + else + image_log(img->log, "It's encrypted with NULL password. OK!\n"); + } else { + if (password) + image_log(img->log, "Password \"%s\": WRONG\n", password); + else + image_log(img->log, "Please specify password. Seems it's necessery.\n"); + + image_log(img->log, "But we save header_not_decrypted.out with encrypted key block\n"); +#else + if (decode1(mdxHeader + keyBlockOff, password, &ci2) != 0) { +#endif + +#if 0 + FILE *b = fopen("header_not_decrypted.out", "wb"); + fwrite(mdxHeader, 1, decSize + 0x12, b); + fclose(b); +#else +#ifdef ENABLE_IMAGE_LOG + log_warning(img->log, " [MDS ] \"%s\" is an unsupported password-protected file\n", + mdsfile); +#else + warning("\"%s\" is an unsupported password-protected file\n", mdsfile); +#endif + fclose(*fp); + *fp = NULL; +#endif + + return 0; + } + + /* + Seems it's always use one mode AES 256 with GF. */ + encryptInfo.bsize = 32; + encryptInfo.mode = 2; + + u8 *keyblock = mdxHeader + keyBlockOff; + memcpy(encryptInfo.dg, keyblock + 0x50, 0x20); + Gf128Tab64Init(keyblock + 0x50, &encryptInfo.gf_ctx); + aes_encrypt_key(keyblock + 0x70, encryptInfo.bsize, &encryptInfo.encr); + aes_decrypt_key(keyblock + 0x70, encryptInfo.bsize, &encryptInfo.decr); + } else + image_log(img->log, "No encryption detected\n"); + + fclose(*fp); + *fp = NULL; + + /* Dump mdxHeader */ + plat_tempfile(temp_file, "mds_v2", ".tmp"); + image_log(img->log, "\nDumping header into %s... ", nvr_path(temp_file)); + + *fp = plat_fopen64(nvr_path(temp_file), "wb"); + fwrite(mdxHeader, 1, decSize + 0x12, *fp); + fclose(*fp); + + fclose(*fp); + *fp = NULL; + + *fp = plat_fopen64(nvr_path(temp_file), "rb"); + + image_log(img->log, "Done\n"); + return isDVD + 1; +} + static int image_load_mds(cd_image_t *img, const char *mdsfile) { @@ -1949,6 +2171,7 @@ image_load_mds(cd_image_t *img, const char *mdsfile) track_index_t *ci = NULL; track_file_t *tf = NULL; int is_viso = 0; + int version = 1; int last_t = -1; int error; char pathname[MAX_FILENAME_LENGTH]; @@ -1956,9 +2179,11 @@ image_load_mds(cd_image_t *img, const char *mdsfile) mds_hdr_t mds_hdr = { 0 }; mds_sess_block_t mds_sess_block = { 0 }; + mds_v2_sess_block_t mds_v2_sess_block = { 0 }; mds_trk_block_t mds_trk_block = { 0 }; mds_trk_ex_block_t mds_trk_ex_block = { 0 }; mds_footer_t mds_footer = { 0 }; + mds_v2_footer_t mds_v2_footer = { 0 }; mds_dpm_block_t mds_dpm_block = { 0 }; uint32_t mds_dpm_blocks_num = 0x00000000; uint32_t mds_dpm_block_offs = 0x00000000; @@ -1990,27 +2215,56 @@ image_load_mds(cd_image_t *img, const char *mdsfile) if (memcmp(mds_hdr.file_sig, "MEDIA DESCRIPTOR", 16)) { #ifdef ENABLE_IMAGE_LOG - log_warning(img->log, " [MDS ] \"%s\"\n is not an actual MDF file", + log_warning(img->log, " [MDS ] \"%s\" is not an actual MDF file\n", mdsfile); #else - warning("\"%s\"\n is not an actual MDF file", mdsfile); + warning("\"%s\" is not an actual MDF file\n", mdsfile); #endif fclose(fp); return 0; } if (mds_hdr.file_ver[0] == 0x02) { + int mdsx = mdsx_init(); + if (!mdsx) { #ifdef ENABLE_IMAGE_LOG - log_warning(img->log, " [MDS ] \"%s\" is a Daemon Tools encrypted MDS which is not supported\n", - mdsfile); + log_warning(img->log, " [MDS ] Error initializing dynamic library %s\n", mdsfile); #else - warning("\"%s\" is a Daemon Tools encrypted MDS which is not supported\n", mdsfile); + warning("Error initializing dynamic library %s\n", mdsfile); #endif - fclose(fp); - return 0; - } + if (fp != NULL) + fclose(fp); + return 0; + } + + image_log(img->log, "Pass 1.5 (decrypting the Media Descriptor Sheet)...\n"); + + fseek(fp, 0, SEEK_SET); + int ret = mds_decrypt_track_data(img, mdsfile, &fp); - img->is_dvd = (mds_hdr.medium_type >= 0x10); + mdsx_close(); + + if (ret == 0) { +#ifdef ENABLE_IMAGE_LOG + log_warning(img->log, " [MDS ] Error decrypting \"%s\"\n", + mdsfile); +#else + warning("Error decrypting \"%s\"\n", mdsfile); +#endif + if (fp != NULL) + fclose(fp); + return 0; + } else { + img->is_dvd = ret - 1; + version = 2; + + fseek(fp, 0, SEEK_SET); + if (fread(&mds_hdr, 1, sizeof(mds_hdr_t), fp) != sizeof(mds_hdr_t)) + return 0; + } + image_log(img->log, "ret = %i\n", ret); + } else + img->is_dvd = (mds_hdr.medium_type >= 0x10); if (img->is_dvd) { if (mds_hdr.disc_struct_offs != 0x00) { @@ -2056,17 +2310,23 @@ image_load_mds(cd_image_t *img, const char *mdsfile) if (mds_hdr.dpm_blocks_offs != 0x00) { fseek(fp, mds_hdr.dpm_blocks_offs, SEEK_SET); - if (fread(&mds_dpm_blocks_num, 1, sizeof(uint32_t), fp) != sizeof(uint32_t)) + if (LOG_VAR(dbnret) fread(&mds_dpm_blocks_num, 1, sizeof(uint32_t), fp) != sizeof(uint32_t)) { + image_log(img->log, "dbnret = %i (expected: %i)\n", (int) dbnret, (int) sizeof(uint32_t)); return 0; + } if (mds_dpm_blocks_num > 0) for (int b = 0; b < mds_dpm_blocks_num; b++) { fseek(fp, mds_hdr.dpm_blocks_offs + 4 + (b * 4), SEEK_SET); - if (fread(&mds_dpm_block_offs, 1, sizeof(uint32_t), fp) != sizeof(uint32_t)) + if (LOG_VAR(dboret) fread(&mds_dpm_block_offs, 1, sizeof(uint32_t), fp) != sizeof(uint32_t)) { + image_log(img->log, "dboret = %i (expected: %i)\n", (int) dboret, (int) sizeof(uint32_t)); return 0; + } fseek(fp, mds_dpm_block_offs, SEEK_SET); - if (fread(&mds_dpm_block, 1, sizeof(mds_dpm_block_t), fp) != sizeof(mds_dpm_block_t)) + if (LOG_VAR(dbret) fread(&mds_dpm_block, 1, sizeof(mds_dpm_block_t), fp) != sizeof(mds_dpm_block_t)) { + image_log(img->log, "dbret = %i (expected: %i)\n", (int) dbret, (int) sizeof(mds_dpm_block_t)); return 0; + } /* We currently only support the bad sectors block and not (yet) actual DPM. */ if (mds_dpm_block.type == 0x00000002) { @@ -2075,22 +2335,44 @@ image_load_mds(cd_image_t *img, const char *mdsfile) img->bad_sectors = (uint32_t *) malloc(img->bad_sectors_num * sizeof(uint32_t)); fseek(fp, mds_dpm_block_offs + sizeof(mds_dpm_block_t), SEEK_SET); int read_size = img->bad_sectors_num * sizeof(uint32_t); - if (fread(img->bad_sectors, 1, read_size, fp) != read_size) + if (LOG_VAR(dbtret) fread(img->bad_sectors, 1, read_size, fp) != read_size) { + image_log(img->log, "dbtret = %i (expected: %i)\n", (int) dbtret, (int) read_size); return 0; + } break; } } } for (int s = 0; s < mds_hdr.sess_num; s++) { - fseek(fp, mds_hdr.sess_blocks_offs + (s * sizeof(mds_sess_block_t)), SEEK_SET); - if (fread(&mds_sess_block, 1, sizeof(mds_sess_block_t), fp) != sizeof(mds_sess_block_t)) - return 0; + if (version == 2) { + fseek(fp, mds_hdr.sess_blocks_offs + (s * sizeof(mds_v2_sess_block_t)), SEEK_SET); + if (LOG_VAR(hret) fread(&mds_v2_sess_block, 1, sizeof(mds_v2_sess_block_t), fp) != sizeof(mds_v2_sess_block_t)) { + image_log(img->log, "hret = %i (expected: %i)\n", (int) hret, (int) sizeof(mds_v2_sess_block_t)); + return 0; + } + memcpy(&mds_sess_block, &mds_v2_sess_block, sizeof(mds_sess_block_t)); + mds_sess_block.sess_start = (int32_t) mds_v2_sess_block.sess_start; + mds_sess_block.sess_end = (int32_t) mds_v2_sess_block.sess_end; + } else { + fseek(fp, mds_hdr.sess_blocks_offs + (s * sizeof(mds_sess_block_t)), SEEK_SET); + if (LOG_VAR(hret2) fread(&mds_sess_block, 1, sizeof(mds_sess_block_t), fp) != sizeof(mds_sess_block_t)) { + image_log(img->log, "hret2 = %i (expected: %i)\n", (int) hret2, (int) sizeof(mds_sess_block_t)); + return 0; + } + } for (int t = 0; t < mds_sess_block.all_blocks_num; t++) { fseek(fp, mds_sess_block.trk_blocks_offs + (t * sizeof(mds_trk_block_t)), SEEK_SET); - if (fread(&mds_trk_block, 1, sizeof(mds_trk_block_t), fp) != sizeof(mds_trk_block_t)) + if (LOG_VAR(tbret) fread(&mds_trk_block, 1, sizeof(mds_trk_block_t), fp) != sizeof(mds_trk_block_t)) { + image_log(img->log, "tbret = %i (expected: %i)\n", (int) tbret, (int) sizeof(mds_trk_block)); return 0; + } + + if (version == 2) { + image_log(img->log, "Start sector V2: %016" PRIX64 "\n", mds_trk_block.start_sect_v2); + mds_trk_block.start_sect = (uint32_t) mds_trk_block.start_sect_v2; + } if (last_t != -1) { /* @@ -2117,8 +2399,10 @@ image_load_mds(cd_image_t *img, const char *mdsfile) mds_trk_ex_block.trk_sectors = mds_trk_block.ex_offs; } else if (mds_trk_block.ex_offs != 0ULL) { fseek(fp, mds_trk_block.ex_offs, SEEK_SET); - if (fread(&mds_trk_ex_block, 1, sizeof(mds_trk_ex_block), fp) != sizeof(mds_trk_ex_block)) + if (LOG_VAR(tret) fread(&mds_trk_ex_block, 1, sizeof(mds_trk_ex_block), fp) != sizeof(mds_trk_ex_block)) { + image_log(img->log, "tret = %i (expected: %i)\n", (int) tret, (int) sizeof(mds_trk_ex_block)); return 0; + } } uint32_t astart = mds_trk_block.start_sect - mds_trk_ex_block.pregap; @@ -2126,35 +2410,61 @@ image_load_mds(cd_image_t *img, const char *mdsfile) uint32_t aend2 = aend + mds_trk_ex_block.trk_sectors; uint32_t astart2 = mds_trk_block.start_sect + mds_trk_ex_block.trk_sectors; + ct->skip = 0; + if (mds_trk_block.footer_offs != 0ULL) for (uint32_t ff = 0; ff < mds_trk_block.files_num; ff++) { - fseek(fp, mds_trk_block.footer_offs + (ff * sizeof(mds_footer_t)), SEEK_SET); - if (fread(&mds_footer, 1, sizeof(mds_footer_t), fp) != sizeof(mds_footer_t)) - return 0; + if (version == 2) { + fseek(fp, mds_trk_block.footer_offs + (ff * sizeof(mds_v2_footer_t)), SEEK_SET); + if (LOG_VAR(fret) fread(&mds_v2_footer, 1, sizeof(mds_v2_footer_t), fp) != sizeof(mds_v2_footer_t)) { + image_log(img->log, "fret = %i (expected: %i)\n", (int) fret, (int) sizeof(mds_v2_footer_t)); + return 0; + } + memcpy(&mds_footer, &mds_v2_footer, sizeof(mds_footer)); + mds_footer.fn_is_wide = 1; + } else { + fseek(fp, mds_trk_block.footer_offs + (ff * sizeof(mds_footer_t)), SEEK_SET); + if (LOG_VAR(fret2) fread(&mds_footer, 1, sizeof(mds_footer_t), fp) != sizeof(mds_footer_t)) { + image_log(img->log, "fret2 = %i (expected: %i)\n", (int) fret2, (int) sizeof(mds_footer_t)); + return 0; + } + } uint16_t wfn[2048] = { 0 }; char fn[2048] = { 0 }; - fseek(fp, mds_footer.fn_offs, SEEK_SET); - if (mds_footer.fn_is_wide) { - for (int i = 0; i < 256; i++) { - if (fread(&(wfn[i]), 1, 2, fp) != 2) + + if (mds_footer.fn_offs == 0x00000000) { + /* This is in MDX files - the file name string is empty. */ + strcpy(fn, mdsfile); + ct->skip = 0x40; + } else { + fseek(fp, mds_footer.fn_offs, SEEK_SET); + if (mds_footer.fn_is_wide) { + for (int i = 0; i < 256; i++) { + if (LOG_VAR(fnret) fread(&(wfn[i]), 1, 2, fp) != 2) { + image_log(img->log, "fnret = %i (expected: %i)\n", (int) fnret, (int) 2); + return 0; + } + if (wfn[i] == 0x0000) + break; + } + (void) utf16_to_utf8(wfn, 2048, (uint8_t *) fn, 2048); + } else for (int i = 0; i < 512; i++) { + if (LOG_VAR(fnret2) fread(&fn[i], 1, 1, fp) != 1) { + image_log(img->log, "fnret2 = %i (expected: %i)\n", (int) fnret2, (int) 1); return 0; - if (wfn[i] == 0x0000) + } + if (fn[i] == 0x00) break; } - (void) utf16_to_utf8(wfn, 2048, (uint8_t *) fn, 2048); - } else for (int i = 0; i < 512; i++) { - if (fread(&fn[i], 1, 1, fp) != 1) - return 0; - if (fn[i] == 0x00) - break; - } - if (!stricmp(fn, "*.mdf")) { - strcpy(fn, mdsfile); - fn[strlen(mdsfile) - 3] = 'm'; - fn[strlen(mdsfile) - 2] = 'd'; - fn[strlen(mdsfile) - 1] = 'f'; + if (!stricmp(fn, "*.mdf")) { + strcpy(fn, mdsfile); + fn[strlen(mdsfile) - 3] = 'm'; + fn[strlen(mdsfile) - 2] = 'd'; + fn[strlen(mdsfile) - 1] = 'f'; + } } + image_log(img->log, "fn = \"%s\"\n", fn); char filename[2048] = { 0 }; if (!path_abs(fn)) @@ -2200,7 +2510,7 @@ image_load_mds(cd_image_t *img, const char *mdsfile) success = 1; if (((ct->sector_size == 2336) || (ct->sector_size == 2332)) && (ct->mode == 2) && (ct->form == 1)) - ct->skip = 8; + ct->skip += 8; ci = &(ct->idx[0]); if (ct->point < 0xa0) { @@ -2217,7 +2527,7 @@ image_load_mds(cd_image_t *img, const char *mdsfile) ci->start = aend + 150; ci->length = mds_trk_ex_block.trk_sectors; ci->type = INDEX_NORMAL; - ci->file_start = mds_trk_block.start_offs / ct->sector_size; + ci->file_start = (mds_trk_block.start_offs - (ct->skip & 0x40)) / ct->sector_size; ci->file_length = ci->length; ci->file = tf; } else { @@ -2653,6 +2963,11 @@ image_close(void *local) free(img->bad_sectors); free(img); + + if (temp_file[0] != 0x00) { + remove(temp_file); + temp_file[0] = 0x00; + } } } @@ -2681,7 +2996,8 @@ image_open(cdrom_t *dev, const char *path) if (img != NULL) { int ret; const int is_cue = ((ext == 4) && !stricmp(path + strlen(path) - ext + 1, "CUE")); - const int is_mds = ((ext == 4) && !stricmp(path + strlen(path) - ext + 1, "MDS")); + const int is_mds = ((ext == 4) && (!stricmp(path + strlen(path) - ext + 1, "MDS") || + !stricmp(path + strlen(path) - ext + 1, "MDX"))); char n[1024] = { 0 }; sprintf(n, "CD-ROM %i Image", dev->id + 1); diff --git a/src/chipset/acc2036.c b/src/chipset/acc2036.c index 3984f82e0ce..9f039c4b93a 100644 --- a/src/chipset/acc2036.c +++ b/src/chipset/acc2036.c @@ -123,7 +123,8 @@ acc2036_recalc(acc2036_t *dev) ram_page_t *ep = &dev->ems_pages[i - start_i]; mem_mapping_disable(&rp->mapping); - mem_mapping_set_addr(&ep->mapping, ep->virt, 0x000040000); + ep->virt = ((i << 14) + 0x000a0000); + mem_mapping_set_addr(&ep->mapping, ep->virt, 0x00004000); mem_mapping_set_exec(&ep->mapping, ram + ep->phys); mem_set_mem_state_both(ep->virt, 0x00004000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); } else { @@ -135,7 +136,7 @@ acc2036_recalc(acc2036_t *dev) int flags; uint8_t val; - mem_mapping_set_addr(&rp->mapping, rp->virt, 0x000040000); + mem_mapping_set_addr(&rp->mapping, rp->virt, 0x00004000); mem_mapping_set_exec(&rp->mapping, ram + rp->phys); if ((i >= 8) && (i <= 15)) { @@ -203,6 +204,8 @@ acc2036_recalc(acc2036_t *dev) mem_remap_top(384); } + mem_mapping_disable(&ram_mid_mapping); + flushmmucache_nopc(); } diff --git a/src/chipset/intel_piix.c b/src/chipset/intel_piix.c index 32df440981e..c6f6486d1e3 100644 --- a/src/chipset/intel_piix.c +++ b/src/chipset/intel_piix.c @@ -1580,7 +1580,10 @@ piix_init(const device_t *info) dev->usb = device_add(&usb_device); if (dev->type > 3) { - dev->nvr = device_add(&piix4_nvr_device); + if (!strcmp(machine_get_internal_name(), "ms5156")) + dev->nvr = device_add(&piix4_ami_1995_nvr_device); + else + dev->nvr = device_add(&piix4_nvr_device); dev->smbus = device_add(&piix4_smbus_device); dev->acpi = device_add(&acpi_intel_device); diff --git a/src/chipset/vl82c480.c b/src/chipset/vl82c480.c index 8015137e089..2ab17eadd0e 100644 --- a/src/chipset/vl82c480.c +++ b/src/chipset/vl82c480.c @@ -28,8 +28,6 @@ #include <86box/port_92.h> #include <86box/chipset.h> -#define machine_at_prolineamt_init NULL /* checks for a removed machine */ - typedef struct vl82c480_t { uint8_t idx; uint8_t regs[256]; @@ -133,7 +131,7 @@ vl82c480_write(uint16_t addr, uint8_t val, void *priv) case 0x02: case 0x03: dev->regs[dev->idx] = val; if ((machines[machine].init == machine_at_martin_init) || - (machines[machine].init == machine_at_prolineamt_init)) + (machines[machine].init == machine_at_monsoon_init)) vl82c480_recalc_banks(dev); break; case 0x04: @@ -220,9 +218,10 @@ vl82c480_init(const device_t *info) vl82c480_t *dev = (vl82c480_t *) calloc(1, sizeof(vl82c480_t)); uint32_t sizes[8] = { 0, 0, 1024, 2048, 4096, 8192, 16384, 32768 }; uint32_t ms = mem_size; - uint8_t min_i = (machines[machine].init == machine_at_prolineamt_init) ? 1 : 0; - uint8_t min_j = (machines[machine].init == machine_at_prolineamt_init) ? 4 : 2; - uint8_t max_j = (machines[machine].init == machine_at_prolineamt_init) ? 8 : 7; + uint8_t min_i = (machines[machine].init == machine_at_monsoon_init) ? 1 : 0; + uint8_t max_i = (machines[machine].init == machine_at_monsoon_init) ? 2 : 4; + uint8_t min_j = (machines[machine].init == machine_at_monsoon_init) ? 2 : 2; + uint8_t max_j = (machines[machine].init == machine_at_monsoon_init) ? 7 : 7; dev->regs[0x00] = info->local; dev->regs[0x01] = 0xff; @@ -233,15 +232,15 @@ vl82c480_init(const device_t *info) dev->regs[0x07] = 0x21; dev->regs[0x08] = 0x38; - if (machines[machine].init == machine_at_prolineamt_init) { - dev->banks[0] = 4096; - - /* Bank 0 is ignored if 64 MB is installed. */ - if (ms != 65536) - ms -= 4096; + if (machines[machine].init == machine_at_monsoon_init) { + if (ms >= 16384) { + dev->banks[0] = 0; + min_i = 0; + } else + dev->banks[0] = 4096; } - if (ms > 0) for (uint8_t i = min_i; i < 4; i++) { + if (ms > 0) for (uint8_t i = min_i; i < max_i; i++) { for (uint8_t j = min_j; j < max_j; j++) { if (ms >= sizes[j]) dev->banks[i] = sizes[j]; diff --git a/src/codegen_new/codegen.c b/src/codegen_new/codegen.c index 875dd72ca15..fcdc1d9482e 100644 --- a/src/codegen_new/codegen.c +++ b/src/codegen_new/codegen.c @@ -676,7 +676,6 @@ codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_p if ((recomp_op_table == recomp_opcodes) && (opcode == 0x48)) goto codegen_skip; #endif - if (in_lock && ((opcode == 0x90) || (opcode == 0xec))) goto codegen_skip; diff --git a/src/codegen_new/codegen_allocator.c b/src/codegen_new/codegen_allocator.c index 4719dfc399f..c3fca66b748 100644 --- a/src/codegen_new/codegen_allocator.c +++ b/src/codegen_new/codegen_allocator.c @@ -7,6 +7,7 @@ # include #endif +#include #include #include #include @@ -18,10 +19,64 @@ #include "codegen.h" #include "codegen_allocator.h" +#include "codegen_backend.h" + +struct mem_code_block_t; + +typedef struct mem_code_block_t +{ + struct mem_code_block_t* prev; + struct mem_code_block_t* next; + + int number; +} mem_code_block_t; + +static bool valid_code_blocks[BLOCK_SIZE]; +static mem_code_block_t mem_code_blocks[BLOCK_SIZE]; +static mem_code_block_t* mem_code_block_head = NULL; +static mem_code_block_t* mem_code_block_tail = NULL; + +static void +remove_from_block_list(mem_code_block_t* block) +{ + valid_code_blocks[block->number] = 0; + if (block->prev) { + block->prev->next = block->next; + if (block->next) { + block->next->prev = block->prev; + } else { + mem_code_block_tail = block->prev; + } + } else if (block->next) { + mem_code_block_head = block->next; + if (mem_code_block_head && mem_code_block_head->next) { + mem_code_block_head->next->prev = mem_code_block_head; + } + } else if (block == mem_code_block_head) { + mem_code_block_head = mem_code_block_tail = NULL; + } + block->next = block->prev = NULL; +} + +static void +add_to_block_list(int code_block) +{ + if (!mem_code_block_head) { + mem_code_block_head = &mem_code_blocks[code_block]; + mem_code_block_head->number = code_block; + mem_code_block_tail = mem_code_block_head; + } else { + mem_code_block_tail->next = &mem_code_blocks[code_block]; + mem_code_blocks[code_block].prev = mem_code_block_tail; + mem_code_block_tail = &mem_code_blocks[code_block]; + mem_code_blocks[code_block].number = code_block; + } +} typedef struct mem_block_t { uint32_t offset; /*Offset into mem_block_alloc*/ uint32_t next; + uint32_t tail; uint16_t code_block; } mem_block_t; @@ -39,6 +94,7 @@ codegen_allocator_init(void) for (uint32_t c = 0; c < MEM_BLOCK_NR; c++) { mem_blocks[c].offset = c * MEM_BLOCK_SIZE; mem_blocks[c].code_block = BLOCK_INVALID; + mem_blocks[c].tail = 0; if (c < MEM_BLOCK_NR - 1) mem_blocks[c].next = c + 2; else @@ -53,15 +109,26 @@ codegen_allocator_allocate(mem_block_t *parent, int code_block) mem_block_t *block; uint32_t block_nr; - while (!mem_block_free_list) { - /*Pick a random memory block and free the owning code block*/ - block_nr = rand() & MEM_BLOCK_MASK; - block = &mem_blocks[block_nr]; - - if (block->code_block && block->code_block != code_block) - codegen_delete_block(&codeblock[block->code_block]); + if (!mem_block_free_list) { + if (mem_code_block_head == mem_code_block_tail) { + fatal("Out of memory blocks!\n"); + } else { + mem_code_block_t* mem_code_block = mem_code_block_head; + while (mem_code_block) { + if (code_block != mem_code_block->number) { + codegen_delete_block(&codeblock[mem_code_block->number]); + } + mem_code_block = mem_code_block->next; + } + + if (mem_block_free_list) + goto block_allocate; + + fatal("Out of memory blocks!\n"); + } } +block_allocate: /*Remove from free list*/ block_nr = mem_block_free_list; block = &mem_blocks[block_nr - 1]; @@ -70,10 +137,21 @@ codegen_allocator_allocate(mem_block_t *parent, int code_block) block->code_block = code_block; if (parent) { /*Add to parent list*/ - block->next = parent->next; - parent->next = block_nr; - } else - block->next = 0; + if (parent->tail) { + mem_blocks[parent->tail - 1].next = block_nr; + parent->tail = block_nr; + } + else + parent->next = parent->tail = block_nr; + block->next = block->tail = 0; + } else { + block->next = block->tail = 0; + + if (!valid_code_blocks[code_block]) { + valid_code_blocks[code_block] = 1; + add_to_block_list(code_block); + } + } codegen_allocator_usage++; return block; @@ -83,6 +161,10 @@ codegen_allocator_free(mem_block_t *block) { int block_nr = (((uintptr_t) block - (uintptr_t) mem_blocks) / sizeof(mem_block_t)) + 1; + block->tail = 0; + if (valid_code_blocks[block->code_block]) + remove_from_block_list(&mem_code_blocks[block->code_block]); + while (1) { int next_block_nr = block->next; codegen_allocator_usage--; @@ -110,11 +192,7 @@ codegen_allocator_clean_blocks(UNUSED(struct mem_block_t *block)) { #if defined __ARM_EABI__ || defined __aarch64__ || defined _M_ARM64 while (1) { -# ifndef _MSC_VER __clear_cache(&mem_block_alloc[block->offset], &mem_block_alloc[block->offset + MEM_BLOCK_SIZE]); -# else - FlushInstructionCache(GetCurrentProcess(), &mem_block_alloc[block->offset], MEM_BLOCK_SIZE); -# endif if (block->next) block = &mem_blocks[block->next - 1]; else diff --git a/src/codegen_new/codegen_block.c b/src/codegen_new/codegen_block.c index ff82384bedd..97dd4927bf2 100644 --- a/src/codegen_new/codegen_block.c +++ b/src/codegen_new/codegen_block.c @@ -559,6 +559,10 @@ codegen_block_start_recompile(codeblock_t *block) fatal("Recompile to used block!\n"); #endif + if (block->head_mem_block) { + codegen_allocator_free(block->head_mem_block); + block->head_mem_block = NULL; + } block->head_mem_block = codegen_allocator_allocate(NULL, block_current); block->data = codeblock_allocator_get_ptr(block->head_mem_block); diff --git a/src/codegen_new/codegen_ops.c b/src/codegen_new/codegen_ops.c index 68861ff5257..70481343b1b 100644 --- a/src/codegen_new/codegen_ops.c +++ b/src/codegen_new/codegen_ops.c @@ -258,6 +258,7 @@ RecompOpFn recomp_opcodes_d8[512] = { RecompOpFn recomp_opcodes_d9[512] = { // clang-format off + /* TODO: Fix the recompilation of D9 44 so Blood II's gameplay music no longer breaks! */ /*16-bit data*/ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ /*00*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -265,7 +266,7 @@ RecompOpFn recomp_opcodes_d9[512] = { /*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, -/*40*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*40*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*50*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, /*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, @@ -287,7 +288,7 @@ RecompOpFn recomp_opcodes_d9[512] = { /*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, -/*40*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*40*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*50*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, /*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, diff --git a/src/config.c b/src/config.c index 86dc95ccaf1..52eb05daeb9 100644 --- a/src/config.c +++ b/src/config.c @@ -51,6 +51,7 @@ #include <86box/lpt.h> #include <86box/serial.h> #include <86box/hdd.h> +#include <86box/hdd_audio.h> #include <86box/hdc.h> #include <86box/hdc_ide.h> #include <86box/fdd.h> @@ -349,16 +350,21 @@ load_machine(void) for (i = 0; machine_migrations[i].old; i++) { if (!strcmp(p, machine_migrations[i].old)) { machine = machine_get_machine_from_internal_name(machine_migrations[i].new); - migrate_from = p; - if (machine_migrations[i].new_bios) { - migration_cat = ini_find_or_create_section(config, machine_get_device(machine)->name); - ini_section_set_string(migration_cat, "bios", machine_migrations[i].new_bios); + if (machine != -1) { + migrate_from = p; + if (machine_migrations[i].new_bios) { + migration_cat = ini_find_or_create_section(config, machine_get_device(machine)->name); + ini_section_set_string(migration_cat, "bios", machine_migrations[i].new_bios); + } } break; } } - if (!migrate_from) + if (!migrate_from) { machine = machine_get_machine_from_internal_name(p); + if (machine == -1) + machine = 0; + } } else { machine = 0; } @@ -408,8 +414,7 @@ load_machine(void) p = ini_section_get_string(cat, "cpu_family", NULL); if (p) { /* Migrate CPU family changes. */ - if ((!strcmp(machines[machine].internal_name, "deskpro386") || - !strcmp(machines[machine].internal_name, "deskpro386_05_1988"))) + if (machines[machine].init == machine_at_deskpro386_init) cpu_f = cpu_get_family("i386dx_deskpro386"); else cpu_f = cpu_get_family(p); @@ -740,6 +745,25 @@ load_sound(void) } } + /* Correct Aztech codec selection in old configs so the OPTi 930 AD1848 type isn't selected */ + for (int i = 0; i < (sizeof(sound_card_current) / sizeof(sound_card_current[0])); i++) { + sprintf(temp, "Aztech Sound Galaxy Pro 16 AB (Washington) #%i", i + 1); + ini_section_t c = ini_find_section(config, temp); + if (c != NULL) { + if (ini_section_get_int(c, "codec", 1) == 2) + ini_section_set_int(c, "codec", 3); + } + } + for (int i = 0; i < (sizeof(sound_card_current) / sizeof(sound_card_current[0])); i++) { + sprintf(temp, "Aztech Sound Galaxy Nova 16 Extra (Clinton) #%i", i + 1); + ini_section_t c = ini_find_section(config, temp); + if (c != NULL) { + if (ini_section_get_int(c, "codec", 1) == 2) + ini_section_set_int(c, "codec", 3); + } + } + + memset(temp, '\0', sizeof(temp)); p = ini_section_get_string(cat, "sound_type", "float"); if (strlen(p) > 511) @@ -785,8 +809,8 @@ load_network(void) nc->net_type = NET_TYPE_VDE; else if (!strcmp(p, "tap") || !strcmp(p, "4")) nc->net_type = NET_TYPE_TAP; - else if (!strcmp(p, "nmswitch") || !strcmp(p, "5")) - nc->net_type = NET_TYPE_NMSWITCH; + else if (!strcmp(p, "nlswitch") || !strcmp(p, "nmswitch") || !strcmp(p, "5")) + nc->net_type = NET_TYPE_NLSWITCH; else if (!strcmp(p, "nrswitch") || !strcmp(p, "6")) nc->net_type = NET_TYPE_NRSWITCH; else @@ -837,8 +861,8 @@ load_network(void) nc->net_type = NET_TYPE_VDE; else if (!strcmp(p, "tap") || !strcmp(p, "4")) nc->net_type = NET_TYPE_TAP; - else if (!strcmp(p, "nmswitch") || !strcmp(p, "5")) - nc->net_type = NET_TYPE_NMSWITCH; + else if (!strcmp(p, "nlswitch") || !strcmp(p, "nmswitch") || !strcmp(p, "5")) + nc->net_type = NET_TYPE_NLSWITCH; else if (!strcmp(p, "nrswitch") || !strcmp(p, "6")) nc->net_type = NET_TYPE_NRSWITCH; else @@ -862,18 +886,17 @@ load_network(void) } else strcpy(nc->host_dev_name, "none"); - sprintf(temp, "net_%02i_switch_group", c + 1); - net_cards_conf[c].switch_group = ini_section_get_int(cat, temp, 0); + sprintf(temp, "net_%02i_switch_group", c + 1); + nc->switch_group = ini_section_get_int(cat, temp, NET_SWITCH_GRP_MIN); + if (nc->switch_group < NET_SWITCH_GRP_MIN) + nc->switch_group = NET_SWITCH_GRP_MIN; - sprintf(temp, "net_%02i_promisc", c + 1); - net_cards_conf[c].promisc_mode = ini_section_get_int(cat, temp, 0); + sprintf(temp, "net_%02i_promisc", c + 1); + nc->promisc_mode = ini_section_get_int(cat, temp, 0); - sprintf(temp, "net_%02i_nrs_host", c + 1); - p = ini_section_get_string(cat, temp, NULL); - if (p != NULL) - strncpy(net_cards_conf[c].nrs_hostname, p, sizeof(net_cards_conf[c].nrs_hostname) - 1); - else - strncpy(net_cards_conf[c].nrs_hostname, "", sizeof(net_cards_conf[c].nrs_hostname) - 1); + sprintf(temp, "net_%02i_nrs_host", c + 1); + p = ini_section_get_string(cat, temp, NULL); + strncpy(nc->nrs_hostname, p ? p : "", sizeof(nc->nrs_hostname) - 1); sprintf(temp, "net_%02i_link", c + 1); nc->link_state = ini_section_get_int(cat, temp, @@ -1229,6 +1252,8 @@ load_hard_disks(void) uint32_t board = 0; uint32_t dev = 0; + hdd_audio_load_profiles(); + memset(temp, '\0', sizeof(temp)); for (uint8_t c = 0; c < HDD_NUM; c++) { sprintf(temp, "hdd_%02i_parameters", c + 1); @@ -1297,6 +1322,11 @@ load_hard_disks(void) p = ini_section_get_string(cat, temp, tmp2); hdd[c].speed_preset = hdd_preset_get_from_internal_name(p); + /* Audio Profile */ + sprintf(temp, "hdd_%02i_audio", c + 1); + p = ini_section_get_string(cat, temp, "none"); + hdd[c].audio_profile = hdd_audio_get_profile_by_internal_name(p); + /* MFM/RLL */ sprintf(temp, "hdd_%02i_mfm_channel", c + 1); if (hdd[c].bus_type == HDD_BUS_MFM) @@ -1492,11 +1522,14 @@ load_floppy_and_cdrom_drives(void) sprintf(temp, "fdd_%02i_check_bpb", c + 1); ini_section_delete_var(cat, temp); } - sprintf(temp, "fdd_%02i_audio", c + 1); + sprintf(temp, "fdd_%02i_audio", c + 1); #ifndef DISABLE_FDD_AUDIO - p = ini_section_get_string(cat, temp, "none"); - int prof = fdd_audio_get_profile_by_internal_name(p); - fdd_set_audio_profile(c, prof); + p = ini_section_get_string(cat, temp, "none"); + if (!strcmp(p, "panasonic")) + d = fdd_audio_get_profile_by_internal_name("panasonic_ju4755_40t"); + else + d = fdd_audio_get_profile_by_internal_name(p); + fdd_set_audio_profile(c, d); #else fdd_set_audio_profile(c, 0); #endif @@ -2927,8 +2960,8 @@ save_network(void) case NET_TYPE_TAP: ini_section_set_string(cat, temp, "tap"); break; - case NET_TYPE_NMSWITCH: - ini_section_set_string(cat, temp, "nmswitch"); + case NET_TYPE_NLSWITCH: + ini_section_set_string(cat, temp, "nlswitch"); break; case NET_TYPE_NRSWITCH: ini_section_set_string(cat, temp, "nrswitch"); @@ -2955,26 +2988,22 @@ save_network(void) ini_section_set_int(cat, temp, nc->link_state); sprintf(temp, "net_%02i_switch_group", c + 1); - if (nc->device_num == 0) + if (nc->switch_group == NET_SWITCH_GRP_MIN) ini_section_delete_var(cat, temp); else - ini_section_set_int(cat, temp, net_cards_conf[c].switch_group); + ini_section_set_int(cat, temp, nc->switch_group); sprintf(temp, "net_%02i_promisc", c + 1); - if (nc->device_num == 0) + if (nc->promisc_mode == 0) ini_section_delete_var(cat, temp); else - ini_section_set_int(cat, temp, net_cards_conf[c].promisc_mode); + ini_section_set_int(cat, temp, nc->promisc_mode); sprintf(temp, "net_%02i_nrs_host", c + 1); - if (nc->device_num == 0) + if (nc->nrs_hostname[0] == '\0') ini_section_delete_var(cat, temp); - else { - if (nc->nrs_hostname[0] != '\0') - ini_section_set_string(cat, temp, net_cards_conf[c].nrs_hostname); - else - ini_section_delete_var(cat, temp); - } + else + ini_section_set_string(cat, temp, net_cards_conf[c].nrs_hostname); } ini_delete_section_if_empty(config, cat); @@ -3437,6 +3466,17 @@ save_hard_disks(void) ini_section_delete_var(cat, temp); else ini_section_set_string(cat, temp, hdd_preset_get_internal_name(hdd[c].speed_preset)); + + sprintf(temp, "hdd_%02i_audio", c + 1); + if (!hdd_is_valid(c) || hdd[c].audio_profile == 0) { + ini_section_delete_var(cat, temp); + } else { + const char *internal_name = hdd_audio_get_profile_internal_name(hdd[c].audio_profile); + if (internal_name && strcmp(internal_name, "none") != 0) + ini_section_set_string(cat, temp, internal_name); + else + ini_section_delete_var(cat, temp); + } } ini_delete_section_if_empty(config, cat); diff --git a/src/cpu/386.c b/src/cpu/386.c index ed4b40ab2f8..7c352ea1943 100644 --- a/src/cpu/386.c +++ b/src/cpu/386.c @@ -237,7 +237,7 @@ exec386_2386(int32_t cycs) cycles += cycs; while (cycles > 0) { - cycle_period = (timer_target - (uint32_t) tsc) + 1; + cycle_period = (timer_target - (uint64_t) tsc) + 1; x86_was_reset = 0; cycdiff = 0; @@ -411,7 +411,7 @@ exec386_2386(int32_t cycs) fatal("Life expired\n"); } - if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t) tsc)) + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint64_t) tsc)) timer_process(); #ifdef USE_GDBSTUB diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index ff729e4cfe4..c3ca9a8defc 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -51,6 +51,7 @@ #define CPU_BLOCK_END() cpu_block_end = 1 +int cpu_force_interpreter = 0; int cpu_override_dynarec = 0; int inrecomp = 0; int cpu_block_end = 0; @@ -279,7 +280,7 @@ update_tsc(void) tsc += cycdiff; if (cycdiff > 0) { - if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t) tsc)) + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint64_t) tsc)) timer_process(); } } @@ -778,7 +779,7 @@ exec386_dynarec(int32_t cycs) cycles_old = cycles; oldtsc = tsc; tsc_old = tsc; - if ((!CACHE_ON()) || cpu_override_dynarec) /*Interpret block*/ + if (cpu_force_interpreter || cpu_override_dynarec || (!CACHE_ON())) /*Interpret block*/ { exec386_dynarec_int(); } else { @@ -864,7 +865,7 @@ exec386_dynarec(int32_t cycs) } if (cycdiff > 0) { - if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t) tsc)) + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint64_t) tsc)) timer_process(); } @@ -893,7 +894,7 @@ exec386(int32_t cycs) cycles += cycs; while (cycles > 0) { - cycle_period = (timer_target - (uint32_t) tsc) + 1; + cycle_period = (timer_target - (uint64_t) tsc) + 1; x86_was_reset = 0; cycdiff = 0; @@ -1077,7 +1078,7 @@ exec386(int32_t cycs) fatal("Life expired\n"); } - if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t) tsc)) + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint64_t) tsc)) timer_process(); #ifdef USE_GDBSTUB diff --git a/src/cpu/808x.c b/src/cpu/808x.c index 14e56f23a35..4e2e830d0e7 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -272,7 +272,7 @@ clock_end(void) /* On 808x systems, clock speed is usually crystal frequency divided by an integer. */ tsc += (uint64_t) diff * ((uint64_t) xt_cpu_multi >> 32ULL); /* Shift xt_cpu_multi by 32 bits to the right and then multiply. */ - if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t) tsc)) + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint64_t) tsc)) timer_process(); } diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 9f6ce23cccf..865e76ffb28 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -446,16 +446,14 @@ typedef struct { # define CPU_STATUS_MASK 0xffff0000 #endif -#ifdef _MSC_VER -# define COMPILE_TIME_ASSERT(expr) /*nada*/ + +#ifdef EXTREME_DEBUG +# define COMPILE_TIME_ASSERT(expr) typedef char COMP_TIME_ASSERT[(expr) ? 1 : 0]; #else -# ifdef EXTREME_DEBUG -# define COMPILE_TIME_ASSERT(expr) typedef char COMP_TIME_ASSERT[(expr) ? 1 : 0]; -# else -# define COMPILE_TIME_ASSERT(expr) /*nada*/ -# endif +# define COMPILE_TIME_ASSERT(expr) /*nada*/ #endif + COMPILE_TIME_ASSERT(sizeof(cpu_state_t) <= 128) #define cpu_state_offset(MEMBER) ((uint8_t) ((uintptr_t) &cpu_state.MEMBER - (uintptr_t) &cpu_state - 128)) @@ -823,6 +821,8 @@ extern MMX_REG *MMP[8]; extern uint16_t *MMEP[8]; extern int cpu_block_end; + +extern int cpu_force_interpreter; extern int cpu_override_dynarec; extern void mmx_init(void); diff --git a/src/cpu/x86.c b/src/cpu/x86.c index 1090f22a135..38e50a48872 100644 --- a/src/cpu/x86.c +++ b/src/cpu/x86.c @@ -373,6 +373,8 @@ reset_common(int hard) in_lock = 0; cpu_cpurst_on_sr = 0; + + cpu_force_interpreter = 0; } /* Hard reset. */ diff --git a/src/cpu/x86_ops_inc_dec.h b/src/cpu/x86_ops_inc_dec.h index b33d02f453d..8b9711aaa62 100644 --- a/src/cpu/x86_ops_inc_dec.h +++ b/src/cpu/x86_ops_inc_dec.h @@ -56,16 +56,23 @@ opINCDEC_b_a16(uint32_t fetchdat) if (cpu_state.abrt) return 1; - if (rmdat & 0x38) { - seteab(temp - 1); - if (cpu_state.abrt) - return 1; - setsub8nc(temp, 1); - } else { - seteab(temp + 1); - if (cpu_state.abrt) - return 1; - setadd8nc(temp, 1); + switch (rmdat & 0x38) { + case 0: /* INC r/m8 */ + seteab(temp + 1); + if (cpu_state.abrt) + return 1; + setadd8nc(temp, 1); + break; + case 0x8: /* DEC r/m8 */ + seteab(temp - 1); + if (cpu_state.abrt) + return 1; + setsub8nc(temp, 1); + break; + default: + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + break; } CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0 : 1, 0, (cpu_mod == 3) ? 0 : 1, 0, 0); @@ -83,16 +90,23 @@ opINCDEC_b_a32(uint32_t fetchdat) if (cpu_state.abrt) return 1; - if (rmdat & 0x38) { - seteab(temp - 1); - if (cpu_state.abrt) - return 1; - setsub8nc(temp, 1); - } else { - seteab(temp + 1); - if (cpu_state.abrt) - return 1; - setadd8nc(temp, 1); + switch (rmdat & 0x38) { + case 0: /* INC r/m8 */ + seteab(temp + 1); + if (cpu_state.abrt) + return 1; + setadd8nc(temp, 1); + break; + case 0x8: /* DEC r/m8 */ + seteab(temp - 1); + if (cpu_state.abrt) + return 1; + setsub8nc(temp, 1); + break; + default: + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + break; } CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0 : 1, 0, (cpu_mod == 3) ? 0 : 1, 0, 1); diff --git a/src/cpu/x87_ops.h b/src/cpu/x87_ops.h index e581652d498..4d099885a29 100644 --- a/src/cpu/x87_ops.h +++ b/src/cpu/x87_ops.h @@ -33,9 +33,6 @@ #endif #include "x87_timings.h" -#ifdef _MSC_VER -# include -#endif #include "x87_ops_conv.h" #ifdef ENABLE_FPU_LOG @@ -390,8 +387,7 @@ x87_compare(double a, double b) if ((fpu_type < FPU_287XL) && !(cpu_state.npxc & 0x1000) && ((a == INFINITY) || (a == -INFINITY)) && ((b == INFINITY) || (b == -INFINITY))) eb = ea; -# if !defined(_MSC_VER) || defined(__clang__) - /* Memory barrier, to force GCC to write to the input parameters + /* Memory barrier, to force GCC to write to the input parameters * before the compare rather than after */ __asm volatile("" : @@ -406,17 +402,7 @@ x87_compare(double a, double b) "fnstsw %0\n" : "=m"(result) : "m"(ea), "m"(eb)); -# else - _ReadWriteBarrier(); - _asm - { - fld eb - fld ea - fclex - fcompp - fnstsw result - } -# endif + return result & (FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3); #else @@ -451,7 +437,6 @@ x87_ucompare(double a, double b) #ifdef X87_INLINE_ASM uint32_t result; -# if !defined(_MSC_VER) || defined(__clang__) /* Memory barrier, to force GCC to write to the input parameters * before the compare rather than after */ __asm volatile("" @@ -467,17 +452,6 @@ x87_ucompare(double a, double b) "fnstsw %0\n" : "=m"(result) : "m"(a), "m"(b)); -# else - _ReadWriteBarrier(); - _asm - { - fld b - fld a - fclex - fcompp - fnstsw result - } -# endif return result & (FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3); #else diff --git a/src/device.c b/src/device.c index 98d4794cfed..3ce49ee78fe 100644 --- a/src/device.c +++ b/src/device.c @@ -483,6 +483,61 @@ device_has_config(const device_t *dev) return (c > 0) ? 1 : 0; } +const char * +device_get_bus_name(const device_t *dev) +{ + const char *sbus = NULL; + + if ((dev->flags & (DEVICE_SIDECAR | DEVICE_ISA)) == (DEVICE_SIDECAR | DEVICE_ISA)) + sbus = "ISA/Sidecar"; + else if (dev->flags & DEVICE_SIDECAR) + sbus = "Sidecar"; + else if (dev->flags & DEVICE_XT_KBC) + sbus = "XT KBC"; + else if (dev->flags & DEVICE_ISA16) + sbus = "ISA16"; + else if (dev->flags & DEVICE_AT_KBC) + sbus = "AT KBC"; + else if (dev->flags & DEVICE_PS2_KBC) + sbus = "PS/2 KBC"; + else if (dev->flags & DEVICE_ISA) + sbus = "ISA"; + else if (dev->flags & DEVICE_CBUS) + sbus = "C-BUS"; + else if (dev->flags & DEVICE_PCMCIA) + sbus = "PCMCIA"; + else if (dev->flags & DEVICE_MCA) + sbus = "MCA"; + else if (dev->flags & DEVICE_MCA32) + sbus = "MCA32"; + else if (dev->flags & DEVICE_HIL) + sbus = "HP HIL"; + else if (dev->flags & DEVICE_EISA) + sbus = "EISA"; + else if (dev->flags & DEVICE_AT32) + sbus = "AT/32"; + else if (dev->flags & DEVICE_OLB) + sbus = "OLB"; + else if (dev->flags & DEVICE_VLB) + sbus = "VLB"; + else if (dev->flags & DEVICE_PCI) + sbus = "PCI"; + else if (dev->flags & DEVICE_CARDBUS) + sbus = "CardBus"; + else if (dev->flags & DEVICE_USB) + sbus = "USB"; + else if (dev->flags & DEVICE_AGP) + sbus = "AGP"; + else if (dev->flags & DEVICE_AC97) + sbus = "AMR"; + else if (dev->flags & DEVICE_COM) + sbus = "COM"; + else if (dev->flags & DEVICE_LPT) + sbus = "LPT"; + + return sbus; +} + void device_get_name(const device_t *dev, int bus, char *name) { @@ -497,59 +552,15 @@ device_get_name(const device_t *dev, int bus, char *name) name[0] = 0x00; if (bus) { - if ((dev->flags & (DEVICE_SIDECAR | DEVICE_ISA)) == - (DEVICE_SIDECAR | DEVICE_ISA)) - sbus = "ISA/Sidecar"; - else if (dev->flags & DEVICE_SIDECAR) - sbus = "Sidecar"; - else if (dev->flags & DEVICE_XT_KBC) - sbus = "XT KBC"; - else if (dev->flags & DEVICE_ISA16) - sbus = "ISA16"; - else if (dev->flags & DEVICE_AT_KBC) - sbus = "AT KBC"; - else if (dev->flags & DEVICE_PS2_KBC) - sbus = "PS/2 KBC"; - else if (dev->flags & DEVICE_ISA) - sbus = "ISA"; - else if (dev->flags & DEVICE_CBUS) - sbus = "C-BUS"; - else if (dev->flags & DEVICE_PCMCIA) - sbus = "PCMCIA"; - else if (dev->flags & DEVICE_MCA) - sbus = "MCA"; - else if (dev->flags & DEVICE_MCA32) - sbus = "MCA32"; - else if (dev->flags & DEVICE_HIL) - sbus = "HP HIL"; - else if (dev->flags & DEVICE_EISA) - sbus = "EISA"; - else if (dev->flags & DEVICE_AT32) - sbus = "AT/32"; - else if (dev->flags & DEVICE_OLB) - sbus = "OLB"; - else if (dev->flags & DEVICE_VLB) - sbus = "VLB"; - else if (dev->flags & DEVICE_PCI) - sbus = "PCI"; - else if (dev->flags & DEVICE_CARDBUS) - sbus = "CardBus"; - else if (dev->flags & DEVICE_USB) - sbus = "USB"; - else if (dev->flags & DEVICE_AGP) - sbus = "AGP"; - else if (dev->flags & DEVICE_AC97) - sbus = "AMR"; - else if (dev->flags & DEVICE_COM) - sbus = "COM"; - else if (dev->flags & DEVICE_LPT) - sbus = "LPT"; + sbus = device_get_bus_name(dev); if (sbus != NULL) { /* First concatenate [] before the device's name. */ - strcat(name, "["); - strcat(name, sbus); - strcat(name, "] "); + if (bus > 0) { + strcat(name, "["); + strcat(name, sbus); + strcat(name, "] "); + } /* Then change string from ISA16 to ISA if applicable. */ if (!strcmp(sbus, "ISA16")) diff --git a/src/device/cartridge.c b/src/device/cartridge.c index 639095f72d2..bbcbad6619a 100644 --- a/src/device/cartridge.c +++ b/src/device/cartridge.c @@ -33,7 +33,7 @@ typedef struct cart_t { uint32_t base; } cart_t; -char cart_fns[2][512]; +char cart_fns[2][MAX_IMAGE_PATH_LEN]; char *cart_image_history[2][CART_IMAGE_HISTORY]; static cart_t carts[2]; diff --git a/src/device/cassette.c b/src/device/cassette.c index 0577ae06fe4..c648139996a 100644 --- a/src/device/cassette.c +++ b/src/device/cassette.c @@ -43,7 +43,7 @@ pc_cassette_t *cassette; -char cassette_fname[512]; +char cassette_fname[MAX_IMAGE_PATH_LEN]; char cassette_mode[512]; char * cassette_image_history[CASSETTE_IMAGE_HISTORY]; unsigned long cassette_pos; @@ -500,7 +500,10 @@ pc_cas_set_motor(pc_cassette_t *cas, unsigned char val) else timer_disable(&cas->timer); - ui_sb_update_icon(SB_CASSETTE, !!val); + if (!cas->save) + ui_sb_update_icon(SB_CASSETTE, !!val); + else + ui_sb_update_icon_write(SB_CASSETTE, !!val); } unsigned char @@ -665,8 +668,12 @@ cassette_callback(void *priv) pc_cas_clock(cas, 8); - if (cas->motor) - ui_sb_update_icon(SB_CASSETTE, 1); + if (cas->motor) { + if (cas->pcm && cas->save) + ui_sb_update_icon_write(SB_CASSETTE, 1); + else + ui_sb_update_icon(SB_CASSETTE, 1); + } timer_advance_u64(&cas->timer, 8ULL * PITCONST); } diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index 0f3bd5600e0..4cb23428edd 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -37,7 +37,6 @@ #include <86box/fdd.h> #include <86box/fdc.h> #include <86box/pci.h> -#include <86box/video.h> #include <86box/keyboard.h> #define STAT_PARITY 0x80 @@ -65,7 +64,6 @@ #define FLAG_CLOCK 0x01 #define FLAG_CACHE 0x02 #define FLAG_PS2 0x04 -#define FLAG_PCI 0x08 enum { STATE_RESET = 0, /* KBC reset state, only accepts command AA. */ @@ -110,6 +108,11 @@ typedef struct atkbc_t { uint8_t is_green; uint8_t kblock_switch; uint8_t is_type2; + uint8_t ami_revision; + uint8_t ami_is_amikey_2; + uint8_t ami_is_megakey; + uint8_t award_revision; + uint8_t chips_revision; uint8_t mem[0x100]; @@ -118,6 +121,8 @@ typedef struct atkbc_t { uint8_t handler_enable[2]; + uint16_t phoenix_revision; + uint16_t base_addr[2]; uint16_t irq[2]; @@ -145,15 +150,6 @@ typedef struct atkbc_t { /* Keyboard controller ports. */ kbc_at_port_t *kbc_at_ports[2] = { NULL, NULL }; -static uint8_t kbc_ami_revision = '8'; -static uint8_t kbc_ami_is_clone = 0; - -static uint8_t kbc_award_revision = 0x42; - -static uint8_t kbc_chips_revision = 0xa6; - -static uint16_t kbc_phoenix_version = 0x0416; - static void (*kbc_at_do_poll)(atkbc_t *dev); /* Non-translated to translated scan codes. */ @@ -474,16 +470,8 @@ kbc_scan_kbd_at(atkbc_t *dev) kbc_ibf_process(dev); /* AT mode. */ } else { -#if 0 - dev->t = dev->mem[0x28]; -#endif - if (dev->mem[0x2e] != 0x00) { -#if 0 - if (!(dev->t & 0x02)) - return; -#endif + if (dev->mem[0x2e] != 0x00) dev->mem[0x2e] = 0x00; - } dev->p2 &= 0xbf; if ((dev->ports[0] != NULL) && (dev->ports[0]->out_new != -1)) { /* In our case, we never have noise on the line, so we can simplify this. */ @@ -543,9 +531,6 @@ kbc_at_poll_at(atkbc_t *dev) /* Keyboard controller command want to output a single byte. */ kbc_at_log("ATkbc: %02X coming from channel %i with high status %02X\n", dev->val, dev->channel, dev->stat_hi); kbc_send_to_ob(dev, dev->val, dev->channel, dev->stat_hi); -#if 0 - dev->state = (dev->pending == 2) ? STATE_KBC_AMI_OUT : STATE_MAIN_IBF; -#endif dev->state = STATE_MAIN_IBF; dev->pending = 0; goto at_main_ibf; @@ -687,12 +672,8 @@ kbc_at_poll_ps2(atkbc_t *dev) /* Keyboard controller command want to output a single byte. */ kbc_at_log("ATkbc: %02X coming from channel %i with high status %02X\n", dev->val, dev->channel, dev->stat_hi); kbc_send_to_ob(dev, dev->val, dev->channel, dev->stat_hi); -#if 0 - dev->state = (dev->pending == 2) ? STATE_KBC_AMI_OUT : STATE_MAIN_IBF; -#endif dev->state = STATE_MAIN_IBF; dev->pending = 0; - // goto ps2_main_ibf; break; case STATE_KBC_OUT: /* Keyboard controller command want to output multiple bytes. */ @@ -772,19 +753,6 @@ write_p2(atkbc_t *dev, uint8_t val) uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; -#if 0 - /* PS/2: Handle IRQ's. */ - if (dev->misc_flags & FLAG_PS2) { - /* IRQ 12 */ - if (dev->irq[1] != 0xffff) - picint_common(1 << dev->irq[1], 0, val & 0x20, NULL); - - /* IRQ 1 */ - if (dev->irq[0] != 0xffff) - picint_common(1 << dev->irq[0], 0, val & 0x10, NULL); - } -#endif - /* AT, PS/2: Handle A20. */ if ((mem_a20_key ^ val) & 0x02) { /* A20 enable change */ mem_a20_key = val & 0x02; @@ -1044,7 +1012,7 @@ write_cmd_ami(void *priv, uint8_t val) break; case 0xa0: /* copyright message */ - switch (kbc_ami_revision) { + switch (dev->ami_revision) { case 0x35: copr = "(C)1994 AMI"; coprlen = strlen(copr) + 1; @@ -1088,7 +1056,7 @@ write_cmd_ami(void *priv, uint8_t val) case 0xa1: /* get controller version */ kbc_at_log("ATkbc: AMI - get controller version\n"); - kbc_delay_to_ob(dev, kbc_ami_revision, 0, 0x00); + kbc_delay_to_ob(dev, dev->ami_revision, 0, 0x00); ret = 0; break; @@ -1160,8 +1128,7 @@ write_cmd_ami(void *priv, uint8_t val) case 0xaf: /* set extended controller RAM */ if ((kbc_ven != KBC_VEN_SIEMENS) && (kbc_ven != KBC_VEN_ALI)) { - if (((kbc_ami_revision >= 'H') && (kbc_ami_revision < 'X')) || - (kbc_ami_revision = '5')) { + if (dev->ami_is_amikey_2) { kbc_at_log("ATkbc: set extended controller RAM\n"); dev->wantdata = 1; dev->state = STATE_KBC_PARAM; @@ -1224,8 +1191,7 @@ write_cmd_ami(void *priv, uint8_t val) break; case 0xc4: - if (((kbc_ami_revision >= 'P') && (kbc_ami_revision < 'X')) || - (kbc_ami_revision = '5')) { + if (dev->ami_is_megakey) { /* set KBC line P14 low */ kbc_at_log("ATkbc: set KBC line P14 (P1 bit 4) low\n"); dev->p1 &= 0xef; @@ -1235,8 +1201,7 @@ write_cmd_ami(void *priv, uint8_t val) } break; case 0xc5: - if (((kbc_ami_revision >= 'P') && (kbc_ami_revision < 'X')) || - (kbc_ami_revision = '5')) { + if (dev->ami_is_megakey) { /* set KBC line P15 low */ kbc_at_log("ATkbc: set KBC line P15 (P1 bit 5) low\n"); dev->p1 &= 0xdf; @@ -1280,8 +1245,7 @@ write_cmd_ami(void *priv, uint8_t val) break; case 0xcc: - if (((kbc_ami_revision >= 'P') && (kbc_ami_revision < 'X')) || - (kbc_ami_revision = '5')) { + if (dev->ami_is_megakey) { /* set KBC line P14 high */ kbc_at_log("ATkbc: set KBC line P14 (P1 bit 4) high\n"); dev->p1 |= 0x10; @@ -1292,8 +1256,7 @@ write_cmd_ami(void *priv, uint8_t val) break; case 0xcd: /* set KBC line P15 high */ - if (((kbc_ami_revision >= 'P') && (kbc_ami_revision < 'X')) || - (kbc_ami_revision = '5')) { + if (dev->ami_is_megakey) { kbc_at_log("ATkbc: set KBC line P15 (P1 bit 5) high\n"); dev->p1 |= 0x20; kbc_delay_to_ob(dev, dev->ob, 0, 0x00); @@ -1512,7 +1475,7 @@ write_cmd_umc(void *priv, uint8_t val) case 0xa1: /* get controller version */ kbc_at_log("ATkbc: UMC - get controller version\n"); - kbc_delay_to_ob(dev, kbc_ami_revision, 0, 0x00); + kbc_delay_to_ob(dev, dev->ami_revision, 0, 0x00); ret = 0; break; } @@ -1567,7 +1530,7 @@ write_cmd_award(void *priv, uint8_t val) case 0xa1: /* get controller version */ kbc_at_log("ATkbc: AMI - get controller version\n"); - kbc_delay_to_ob(dev, kbc_ami_revision, 0, 0x00); + kbc_delay_to_ob(dev, dev->ami_revision, 0, 0x00); ret = 0; break; @@ -1587,7 +1550,7 @@ write_cmd_award(void *priv, uint8_t val) in Norton Commander 3.0. */ case 0xaf: /* read keyboard version */ kbc_at_log("ATkbc: read keyboard version\n"); - kbc_delay_to_ob(dev, kbc_award_revision, 0, 0x00); + kbc_delay_to_ob(dev, dev->award_revision, 0, 0x00); ret = 0; break; @@ -1701,7 +1664,7 @@ write_cmd_data_chips(void *priv, uint8_t val) break; case 0x00: /* return ID */ kbc_at_log("ATkbc: C&T - return ID\n"); - kbc_delay_to_ob(dev, kbc_chips_revision, 0, 0x00); + kbc_delay_to_ob(dev, dev->chips_revision, 0, 0x00); break; case 0x02: /* write input port */ kbc_at_log("ATkbc: C&T - write input port\n"); @@ -1759,6 +1722,13 @@ write_cmd_chips(void *priv, uint8_t val) dev->state = STATE_KBC_PARAM; ret = 0; break; + + case 0xb3: /* Unknown */ + kbc_at_log("ATkbc: C&T - Unknown\n"); + kbc_delay_to_ob(dev, dev->ob, 0, 0x00); + dev->pending++; + ret = 0; + break; } return ret; @@ -1967,8 +1937,8 @@ write_cmd_phoenix(void *priv, uint8_t val) revision level and proper CPU bits. */ case 0xd5: /* Read MultiKey code revision level */ kbc_at_log("ATkbc: Phoenix - Read MultiKey code revision level\n"); - kbc_at_queue_add(dev, kbc_phoenix_version >> 8); - kbc_at_queue_add(dev, kbc_phoenix_version & 0xff); + kbc_at_queue_add(dev, dev->phoenix_revision >> 8); + kbc_at_queue_add(dev, dev->phoenix_revision & 0xff); ret = 0; break; @@ -2201,16 +2171,6 @@ write_cmd_toshiba(void *priv, uint8_t val) t3100e_notify_set(0x00); ret = 0; break; - - case 0xc0: /* Read P1 */ - kbc_at_log("ATkbc: read P1\n"); - - /* The T3100e returns all bits set except bit 6 which - * is set by t3100e_mono_set() */ - dev->p1 = (t3100e_mono_get() & 1) ? 0xff : 0xbf; - kbc_delay_to_ob(dev, dev->p1, 0, 0x00); - ret = 0; - break; } return ret; @@ -2284,7 +2244,13 @@ read_p1(atkbc_t *dev) Compaq: Reserved; NCR: DMA mode. */ - uint8_t ret = machine_get_p1(dev->p1) | (dev->p1 & 0x03); + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + uint8_t ret = 0x00; + + if ((dev != NULL) && (kbc_ven == KBC_VEN_TOSHIBA)) + ret = machine_get_p1(0xff); + else + ret = machine_get_p1(dev->p1) | (dev->p1 & 0x03); dev->p1 = ((dev->p1 + 1) & 0x03) | (dev->p1 & 0xfc); @@ -2787,18 +2753,14 @@ static void kbc_at_reset(void *priv) { atkbc_t *dev = (atkbc_t *) priv; - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; dev->status = STAT_UNLOCKED; dev->mem[0x20] = 0x01; dev->mem[0x20] |= CCB_TRANSLATE; dev->command_phase = 0; - /* Set up the correct Video Type bits. */ - if (!is286 || (kbc_ven == KBC_VEN_ACER)) - dev->p1 = video_is_mda() ? 0xb0 : 0xf0; - else - dev->p1 = video_is_mda() ? 0xf0 : 0xb0; + /* Video Type is now handled in the machine P1 handler. */ + dev->p1 = 0xf0; kbc_at_log("ATkbc: P1 = %02x\n", dev->p1); /* Disabled both the keyboard and auxiliary ports. */ @@ -2810,7 +2772,6 @@ kbc_at_reset(void *priv) dev->sc_or = 0; dev->ami_flags = (machine_has_flags_ex(MACHINE_PS2_KBC)) ? 0x01 : 0x00; - dev->misc_flags &= FLAG_PCI; if (machine_has_flags_ex(MACHINE_PS2_KBC)) { dev->misc_flags |= FLAG_PS2; @@ -2920,12 +2881,8 @@ kbc_at_init(const device_t *info) dev->is_asic = !!(info->local & KBC_FLAG_IS_ASIC); dev->is_type2 = !!(info->local & KBC_FLAG_IS_TYPE2); - video_reset(gfxcard[0]); kbc_at_reset(dev); - if (info->flags & DEVICE_PCI) - dev->misc_flags |= FLAG_PCI; - dev->handlers[0].read = kbc_at_port_1_read; dev->handlers[0].write = kbc_at_port_1_write; dev->handlers[1].read = kbc_at_port_2_read; @@ -2942,12 +2899,13 @@ kbc_at_init(const device_t *info) dev->write_cmd_data_ven = NULL; dev->write_cmd_ven = NULL; - kbc_ami_revision = '8'; - kbc_award_revision = 0x42; + dev->ami_revision = '8'; - kbc_chips_revision = 0xa6; + dev->award_revision = 0x42; - kbc_phoenix_version = 0x0416; + dev->chips_revision = 0xa6; + + dev->phoenix_revision = 0x0416; switch (dev->flags & KBC_VEN_MASK) { default: @@ -2957,9 +2915,9 @@ kbc_at_init(const device_t *info) case KBC_VEN_AWARD: case KBC_VEN_VIA: if ((info->local & 0xff00) != 0x0000) - kbc_ami_revision = (info->local >> 8) & 0xff; + dev->ami_revision = (info->local >> 8) & 0xff; if ((info->local & 0xff0000) != 0x000000) - kbc_award_revision = (info->local >> 16) & 0xff; + dev->award_revision = (info->local >> 16) & 0xff; dev->write_cmd_data_ven = write_cmd_data_award; dev->write_cmd_ven = write_cmd_award; break; @@ -2973,23 +2931,22 @@ kbc_at_init(const device_t *info) break; case KBC_VEN_ALI: - kbc_ami_revision = 'F'; - kbc_award_revision = 0x43; + dev->ami_revision = 'F'; + dev->award_revision = 0x43; dev->write_cmd_data_ven = write_cmd_data_ami; dev->write_cmd_ven = write_cmd_ami; break; case KBC_VEN_AMI_TRIGEM: dev->is_green = !!(info->local & KBC_FLAG_IS_GREEN); - kbc_ami_revision = 'Z'; + dev->ami_revision = 'Z'; dev->write_cmd_data_ven = write_cmd_data_ami; dev->write_cmd_ven = write_cmd_ami; break; case KBC_VEN_AMI: case KBC_VEN_HOLTEK: - kbc_ami_is_clone = !!(info->local & KBC_FLAG_IS_CLONE); - kbc_ami_revision = (info->local >> 8) & 0xff; + dev->ami_revision = (info->local >> 8) & 0xff; dev->write_cmd_data_ven = write_cmd_data_ami; dev->write_cmd_ven = write_cmd_ami; @@ -2997,18 +2954,18 @@ kbc_at_init(const device_t *info) case KBC_VEN_UMC: if ((info->local & 0xff00) != 0x0000) - kbc_ami_revision = (info->local >> 8) & 0xff; + dev->ami_revision = (info->local >> 8) & 0xff; else - kbc_ami_revision = 0x48; + dev->ami_revision = 0x48; dev->write_cmd_ven = write_cmd_umc; break; case KBC_VEN_SIS: if ((info->local & 0xff00) != 0x0000) - kbc_ami_revision = (info->local >> 8) & 0xff; + dev->ami_revision = (info->local >> 8) & 0xff; else - kbc_ami_revision = 0x48; + dev->ami_revision = 0x48; dev->write_cmd_data_ven = write_cmd_data_sis; dev->write_cmd_ven = write_cmd_sis; @@ -3016,14 +2973,14 @@ kbc_at_init(const device_t *info) case KBC_VEN_CHIPS: if ((info->local & 0xff00) != 0x0000) - kbc_chips_revision = (info->local >> 8) & 0xff; + dev->chips_revision = (info->local >> 8) & 0xff; dev->write_cmd_data_ven = write_cmd_data_chips; dev->write_cmd_ven = write_cmd_chips; break; case KBC_VEN_PHOENIX: if ((info->local & 0xffff00) != 0x000000) - kbc_phoenix_version = (info->local >> 8) & 0xffff; + dev->phoenix_revision = (info->local >> 8) & 0xffff; dev->write_cmd_data_ven = write_cmd_data_phoenix; dev->write_cmd_ven = write_cmd_phoenix; break; @@ -3039,6 +2996,11 @@ kbc_at_init(const device_t *info) break; } + dev->ami_is_amikey_2 = ((dev->ami_revision >= 'H') && (dev->ami_revision < 'X')) || + (dev->ami_revision == '5'); + dev->ami_is_megakey = ((dev->ami_revision >= 'P') && (dev->ami_revision < 'X')) || + (dev->ami_revision == '5'); + max_ports = 2; for (int i = 0; i < max_ports; i++) { diff --git a/src/device/kbc_xt.c b/src/device/kbc_xt.c index a9fa8bf6c24..c1a3aee5cb8 100644 --- a/src/device/kbc_xt.c +++ b/src/device/kbc_xt.c @@ -85,6 +85,7 @@ typedef struct xtkbd_t { uint8_t type; uint8_t pravetz_flags; uint8_t cpu_speed; + uint8_t ignore; pc_timer_t send_delay_timer; } xtkbd_t; @@ -96,6 +97,8 @@ static int is_tandy = 0; static int is_t1x00 = 0; static int is_amstrad = 0; +#define kbd_adddata kbd_adddata_xt_common + #ifdef ENABLE_KEYBOARD_XT_LOG int keyboard_xt_do_log = ENABLE_KEYBOARD_XT_LOG; @@ -117,7 +120,6 @@ kbd_log(const char *fmt, ...) static uint8_t get_fdd_switch_settings(void) { - uint8_t fdd_count = 0; for (uint8_t i = 0; i < FDD_NUM; i++) { @@ -134,7 +136,6 @@ get_fdd_switch_settings(void) static uint8_t get_videomode_switch_settings(void) { - if (video_is_mda()) return 0x30; else if (video_is_cga()) @@ -172,8 +173,8 @@ kbd_poll(void *priv) } } -static void -kbd_adddata(uint16_t val) +void +kbd_adddata_xt_common(uint16_t val) { /* Test for T1000 'Fn' key (Right Alt / Right Ctrl) */ if (is_t1x00) { @@ -257,6 +258,98 @@ kbd_adddata_process(uint16_t val, void (*adddata)(uint16_t val)) } } +void +kbd_adddata_process_10x(uint16_t val, void (*adddata)(uint16_t val)) +{ + uint8_t fake_shift[4] = { 0 }; + uint8_t num_lock = 0; + uint8_t shift_states = 0; + + if (!adddata) + return; + + keyboard_get_states(NULL, &num_lock, NULL, NULL); + shift_states = keyboard_get_shift() & STATE_SHIFT_MASK; + + switch (val) { + case FAKE_LSHIFT_ON: + kbd_log("%s: Fake left shift on, scan code: ", dev->name); + if (num_lock) { + if (shift_states) { + kbd_log("N/A (one or both shifts on)\n"); + break; + } else { + /* Num lock on and no shifts are pressed, send non-inverted fake shift. */ + kbd_log("E0 2A\n"); + fake_shift[0] = 0xe0; + fake_shift[1] = 0x2a; + for (int i = 0; i < 2; i++) + adddata(fake_shift[0]); + } + } else { + if (shift_states & STATE_LSHIFT) { + /* Num lock off and left shift pressed. */ + kbd_log("E0 AA\n"); + fake_shift[0] = 0xe0; + fake_shift[1] = 0xaa; + for (int i = 0; i < 2; i++) + adddata(fake_shift[0]); + } + if (shift_states & STATE_RSHIFT) { + /* Num lock off and right shift pressed. */ + kbd_log("E0 B6\n"); + fake_shift[0] = 0xe0; + fake_shift[1] = 0xb6; + for (int i = 0; i < 2; i++) + adddata(fake_shift[0]); + } + kbd_log(shift_states ? "" : "N/A (both shifts off)\n"); + } + break; + + case FAKE_LSHIFT_OFF: + kbd_log("%s: Fake left shift on, scan code: ", dev->name); + if (num_lock) { + if (shift_states) { + kbd_log("N/A (one or both shifts on)\n"); + break; + } else { + /* Num lock on and no shifts are pressed, send non-inverted fake shift. */ + kbd_log("E0 AA\n"); + fake_shift[0] = 0xe0; + fake_shift[1] = 0xaa; + for (int i = 0; i < 2; i++) + adddata(fake_shift[0]); + } + } else { + if (shift_states & STATE_LSHIFT) { + /* Num lock off and left shift pressed. */ + kbd_log("E0 2A\n"); + fake_shift[0] = 0xe0; + fake_shift[1] = 0x2a; + for (int i = 0; i < 2; i++) + adddata(fake_shift[0]); + break; + } + if (shift_states & STATE_RSHIFT) { + /* Num lock off and right shift pressed. */ + kbd_log("E0 36\n"); + fake_shift[0] = 0xe0; + fake_shift[1] = 0x36; + for (int i = 0; i < 2; i++) + adddata(fake_shift[0]); + break; + } + kbd_log(shift_states ? "" : "N/A (both shifts off)\n"); + } + break; + + default: + adddata(val); + break; + } +} + static void kbd_adddata_ex(uint16_t val) { diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index d6fdaf4b71b..21f06df03aa 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -305,7 +305,7 @@ const scancode scancode_set1_at[512] = { { .mk = { 0 }, .brk = { 0 } }, /* 0de */ { .mk = { 0 }, .brk = { 0 } }, /* 0df */ { .mk = { 0 }, .brk = { 0 } }, /* 0e0 */ - { .mk = { 0 }, .brk = { 0 } }, /* 0e1 */ + { .mk = { 0xE1, 0 }, .brk = { 0 } }, /* 0e1 */ { .mk = { 0 }, .brk = { 0 } }, /* 0e2 */ { .mk = { 0 }, .brk = { 0 } }, /* 0e3 */ { .mk = { 0 }, .brk = { 0 } }, /* 0e4 */ @@ -822,7 +822,7 @@ const scancode scancode_set2_at[512] = { { .mk = { 0 }, .brk = { 0 } }, /* 0de */ { .mk = { 0 }, .brk = { 0 } }, /* 0df */ { .mk = { 0 }, .brk = { 0 } }, /* 0e0 */ - { .mk = { 0 }, .brk = { 0 } }, /* 0e1 */ + { .mk = { 0xE1, 0 }, .brk = { 0 } }, /* 0e1 */ { .mk = { 0 }, .brk = { 0 } }, /* 0e2 */ { .mk = { 0 }, .brk = { 0 } }, /* 0e3 */ { .mk = { 0 }, .brk = { 0 } }, /* 0e4 */ @@ -1339,7 +1339,7 @@ const scancode scancode_set1_ax[512] = { { .mk = { 0 }, .brk = { 0 } }, /* 0de */ { .mk = { 0 }, .brk = { 0 } }, /* 0df */ { .mk = { 0 }, .brk = { 0 } }, /* 0e0 */ - { .mk = { 0 }, .brk = { 0 } }, /* 0e1 */ + { .mk = { 0xE1, 0 }, .brk = { 0 } }, /* 0e1 */ { .mk = { 0 }, .brk = { 0 } }, /* 0e2 */ { .mk = { 0 }, .brk = { 0 } }, /* 0e3 */ { .mk = { 0 }, .brk = { 0 } }, /* 0e4 */ @@ -1856,7 +1856,7 @@ const scancode scancode_set2_ax[512] = { { .mk = { 0 }, .brk = { 0 } }, /* 0de */ { .mk = { 0 }, .brk = { 0 } }, /* 0df */ { .mk = { 0 }, .brk = { 0 } }, /* 0e0 */ - { .mk = { 0 }, .brk = { 0 } }, /* 0e1 */ + { .mk = { 0xE1, 0 }, .brk = { 0 } }, /* 0e1 */ { .mk = { 0 }, .brk = { 0 } }, /* 0e2 */ { .mk = { 0 }, .brk = { 0 } }, /* 0e3 */ { .mk = { 0 }, .brk = { 0 } }, /* 0e4 */ @@ -5342,6 +5342,46 @@ add_data_vals(atkbc_dev_t *dev, uint8_t *val, uint8_t len) kbc_at_dev_queue_add(dev, val[i], 1); } +static void +add_data_kbd_84(uint16_t val) +{ + atkbc_dev_t *dev = SavedKbd; + uint8_t fake_shift = 0; + uint8_t num_lock = 0; + uint8_t shift_states = 0; + + keyboard_get_states(NULL, &num_lock, NULL, NULL); + shift_states = keyboard_get_shift() & STATE_LSHIFT; + + /* If NumLock is on, invert the left shift state so we can always check for + the the same way flag being set (and with NumLock on that then means it + is actually *NOT* set). */ + if (num_lock) + shift_states ^= STATE_LSHIFT; + + switch (val) { + case FAKE_LSHIFT_ON: + /* If NumLock is on, fake shifts are sent when shift is *NOT* presed, + if NumLock is off, fake shifts are sent when shift is pressed. */ + if (shift_states) { + /* Send fake shift. */ + fake_shift = num_lock ? 0x2a : 0xaa; + add_data_vals(dev, &fake_shift, 1); + } + break; + case FAKE_LSHIFT_OFF: + if (shift_states) { + /* Send fake shift. */ + fake_shift = num_lock ? 0xaa : 0x2a; + add_data_vals(dev, &fake_shift, 1); + } + break; + default: + kbc_at_dev_queue_add(dev, val, 1); + break; + } +} + static void add_data_kbd(uint16_t val) { @@ -5975,7 +6015,10 @@ keyboard_at_init(const device_t *info) bat_counter = 0x0000; } - keyboard_send = add_data_kbd; + if ((dev->type & FLAG_TYPE_MASK) > KBD_84_KEY) + keyboard_send = add_data_kbd; + else + keyboard_send = add_data_kbd_84; SavedKbd = dev; keyboard_update_states(0, 0, 0, 0); diff --git a/src/device/keyboard_xt.c b/src/device/keyboard_xt.c index d31d5f027d0..0ac25b06143 100644 --- a/src/device/keyboard_xt.c +++ b/src/device/keyboard_xt.c @@ -557,17 +557,32 @@ typedef struct { int type; } kbd_t; +static void +kbd_adddata_xt(uint16_t val) +{ + kbd_adddata_process(val, kbd_adddata_xt_common); +} + +static void +kbd_adddata_xt_10x(uint16_t val) +{ + kbd_adddata_process_10x(val, kbd_adddata_xt_common); +} + static void * kbd_init(const device_t *info) { kbd_t *dev = (kbd_t *) calloc(1, sizeof(kbd_t)); - dev->type = info->local; + dev->type = device_get_config_int("keys"); - if (dev->type == KBD_83_KEY) + if (dev->type == KBD_83_KEY) { keyboard_set_table(scancode_xt); - else + keyboard_send = kbd_adddata_xt; + } else { keyboard_set_table(scancode_set1); + keyboard_send = kbd_adddata_xt_10x; + } return dev; } diff --git a/src/device/mouse.c b/src/device/mouse.c index d4ef4c8733e..5cc94d11642 100644 --- a/src/device/mouse.c +++ b/src/device/mouse.c @@ -34,6 +34,12 @@ #include <86box/plat.h> #include <86box/plat_unused.h> +#ifdef _WIN32 +#define WHEEL_DELTA 120 +#else +#define WHEEL_DELTA 1 +#endif + typedef struct mouse_t { const device_t *device; } mouse_t; @@ -510,16 +516,28 @@ mouse_subtract_z(int *delta_z, int min, int max, int invert) { int z = ATOMIC_LOAD(mouse_z); int real_z = invert ? -z : z; + min *= WHEEL_DELTA; + max *= WHEEL_DELTA; +#if WHEEL_DELTA > 1 + if ((real_z > -WHEEL_DELTA) && (real_z < WHEEL_DELTA)) { + *delta_z = 0; + return; + } else +#endif if (real_z > max) { - *delta_z = max; + *delta_z = max / WHEEL_DELTA; real_z -= max; } else if (real_z < min) { - *delta_z = min; + *delta_z = min / WHEEL_DELTA; real_z += ABS(min); } else { - *delta_z = real_z; + *delta_z = real_z / WHEEL_DELTA; +#if WHEEL_DELTA > 1 + real_z -= ((real_z / WHEEL_DELTA) * WHEEL_DELTA); +#else real_z = 0; +#endif } ATOMIC_STORE(mouse_z, invert ? -real_z : real_z); @@ -530,16 +548,28 @@ mouse_subtract_w(int *delta_w, int min, int max, int invert) { int w = ATOMIC_LOAD(mouse_w); int real_w = invert ? -w : w; + min *= WHEEL_DELTA; + max *= WHEEL_DELTA; +#if WHEEL_DELTA > 1 + if ((real_w > -WHEEL_DELTA) && (real_w < WHEEL_DELTA)) { + *delta_w = 0; + return; + } else +#endif if (real_w > max) { - *delta_w = max; + *delta_w = max / WHEEL_DELTA; real_w -= max; } else if (real_w < min) { - *delta_w = min; + *delta_w = min / WHEEL_DELTA; real_w += ABS(min); } else { - *delta_w = real_w; + *delta_w = real_w / WHEEL_DELTA; +#if WHEEL_DELTA > 1 + real_w -= ((real_w / WHEEL_DELTA) * WHEEL_DELTA); +#else real_w = 0; +#endif } ATOMIC_STORE(mouse_w, invert ? -real_w : real_w); diff --git a/src/device/postcard.c b/src/device/postcard.c index 908adfe7261..f3357445205 100644 --- a/src/device/postcard.c +++ b/src/device/postcard.c @@ -191,7 +191,7 @@ postcard_init(UNUSED(const device_t *info)) if (machine_has_bus(machine, MACHINE_BUS_MCA)) postcard_port = 0x680; /* MCA machines */ else if (strstr(machines[machine].name, " PS/2 ") || - strstr(machine_getname_ex(machine), " PS/1 ")) + strstr(machine_getname(machine), " PS/1 ")) postcard_port = 0x190; /* ISA PS/2 machines */ else if (strstr(machines[machine].name, " IBM XT ")) postcard_port = 0x60; /* IBM XT */ @@ -204,7 +204,7 @@ postcard_init(UNUSED(const device_t *info)) postcard_port = 0x84; /* ISA Compaq machines */ else if (strstr(machines[machine].name, "Olivetti")) postcard_port = 0x378; /* Olivetti machines */ - else if (!strcmp(machines[machine].internal_name, "isa486c")) + else if (machines[machine].init == machine_at_isa486c_init) postcard_port = 0x5080; /* ASUS ISA-486C */ else postcard_port = 0x80; /* AT and clone machines */ diff --git a/src/discord.c b/src/discord.c index 091d4c95f93..3eb5424e920 100644 --- a/src/discord.c +++ b/src/discord.c @@ -91,9 +91,9 @@ discord_update_activity(int paused) #endif if (strlen(vm_name) < 100) { snprintf(activity.details, sizeof(activity.details), "Running \"%s\"", vm_name); - snprintf(activity.state, sizeof(activity.state), "%s (%s/%s)", strchr(machine_getname(), ']') + 2, cpufamily, cpu_s->name); + snprintf(activity.state, sizeof(activity.state), "%s (%s/%s)", strchr(machine_getname(machine), ']') + 2, cpufamily, cpu_s->name); } else { - strncpy(activity.details, strchr(machine_getname(), ']') + 2, sizeof(activity.details) - 1); + strncpy(activity.details, strchr(machine_getname(machine), ']') + 2, sizeof(activity.details) - 1); snprintf(activity.state, sizeof(activity.state), "%s/%s", cpufamily, cpu_s->name); } #pragma GCC diagnostic pop diff --git a/src/disk/CMakeLists.txt b/src/disk/CMakeLists.txt index 9b8d72f54c6..fff17a5e421 100644 --- a/src/disk/CMakeLists.txt +++ b/src/disk/CMakeLists.txt @@ -36,6 +36,7 @@ add_library(hdd OBJECT hdc_ide_sff8038i.c hdc_ide_um8673f.c hdc_ide_w83769f.c + hdd_audio.c ) add_library(rdisk OBJECT rdisk.c) diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 6b116697fdb..7b2b7681629 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -552,8 +552,8 @@ ide_hd_identify(const ide_t *ide) /* Serial Number */ ide_padstr((char *) (ide->buffer + 10), "", 20); /* Firmware */ - if (hdd[ide->hdd_num].version_ex) - ide_padstr((char *) (ide->buffer + 23), hdd[ide->hdd_num].version_ex, 8); + if (hdd[ide->hdd_num].version) + ide_padstr((char *) (ide->buffer + 23), hdd[ide->hdd_num].version, 8); else ide_padstr((char *) (ide->buffer + 23), EMU_VERSION_EX, 8); /* Model */ @@ -3010,6 +3010,36 @@ ide_pnp_config_changed_1addr(uint8_t ld, isapnp_device_config_t *config, void *p } } +/* OPTi 931 PnP ROM flips the main and side IDE I/O port ranges */ +void +ide_pnp_config_changed_opti931(uint8_t ld, isapnp_device_config_t *config, void *priv) +{ + intptr_t board = (intptr_t) priv; + + if (ld) + return; + + if (ide_boards[board]->base[0] || ide_boards[board]->base[1]) { + ide_remove_handlers(board); + ide_boards[board]->base[0] = ide_boards[board]->base[1] = 0; + } + + ide_boards[board]->irq = -1; + + if (config->activate) { + ide_boards[board]->base[1] = (config->io[0].base != ISAPNP_IO_DISABLED) ? + config->io[0].base : 0x0000; + ide_boards[board]->base[0] = (config->io[1].base != ISAPNP_IO_DISABLED) ? + config->io[1].base : 0x0000; + + if (ide_boards[board]->base[0] && ide_boards[board]->base[1]) + ide_set_handlers(board); + + if (config->irq[0].irq != ISAPNP_IRQ_DISABLED) + ide_boards[board]->irq = config->irq[0].irq; + } +} + void ide_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) { diff --git a/src/disk/hdd.c b/src/disk/hdd.c index 357c787b8e0..da4d703d80b 100644 --- a/src/disk/hdd.c +++ b/src/disk/hdd.c @@ -27,6 +27,7 @@ #include <86box/hdd.h> #include <86box/cdrom.h> #include <86box/video.h> +#include <86box/hdd_audio.h> #include "cpu.h" #define HDD_OVERHEAD_TIME 50.0 @@ -38,7 +39,6 @@ hdd_init(void) { /* Clear all global data. */ memset(hdd, 0x00, sizeof(hdd)); - return 0; } @@ -196,6 +196,9 @@ hdd_seek_get_time(hard_disk_t *hdd, uint32_t dst_addr, uint8_t operation, uint8_ } if (!max_seek_time || seek_time <= max_seek_time) { + if (new_cylinder != hdd->cur_cylinder) + hdd_audio_seek(hdd, new_cylinder); + hdd->cur_addr = dst_addr; hdd->cur_track = new_track; hdd->cur_cylinder = new_cylinder; @@ -310,7 +313,7 @@ hdd_timing_write(hard_disk_t *hdd, uint32_t addr, uint32_t len) } } - hdd->cache.write_start_time = tsc + (uint32_t) (seek_time * cpuclock / 1000000.0); + hdd->cache.write_start_time = tsc + (uint64_t) (seek_time * cpuclock / 1000000.0); return seek_time; } @@ -380,7 +383,7 @@ hdd_timing_read(hard_disk_t *hdd, uint32_t addr, uint32_t len) cache->ra_ongoing = 1; cache->ra_segment = active_seg->id; - cache->ra_start_time = tsc + (uint32_t) (seek_time * cpuclock / 1000000.0); + cache->ra_start_time = tsc + (uint64_t) (seek_time * cpuclock / 1000000.0); return seek_time; } @@ -426,145 +429,145 @@ hdd_zones_init(hard_disk_t *hdd) static hdd_preset_t hdd_speed_presets[] = { // clang-format off - { .name = "[Generic] RAM Disk (max. speed)", .internal_name = "ramdisk", .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 32 }, - { .name = "[Generic] 1989 (3500 RPM)", .internal_name = "1989_3500rpm", .zones = 1, .avg_spt = 35, .heads = 2, .rpm = 3500, .full_stroke_ms = 40, .track_seek_ms = 8, .rcache_num_seg = 1, .rcache_seg_size = 16, .max_multiple = 8 }, - { .name = "[Generic] 1992 (3600 RPM)", .internal_name = "1992_3600rpm", .zones = 1, .avg_spt = 45, .heads = 2, .rpm = 3600, .full_stroke_ms = 30, .track_seek_ms = 6, .rcache_num_seg = 4, .rcache_seg_size = 16, .max_multiple = 8 }, - { .name = "[Generic] 1994 (4500 RPM)", .internal_name = "1994_4500rpm", .zones = 8, .avg_spt = 80, .heads = 4, .rpm = 4500, .full_stroke_ms = 26, .track_seek_ms = 5, .rcache_num_seg = 4, .rcache_seg_size = 32, .max_multiple = 16 }, - { .name = "[Generic] 1996 (5400 RPM)", .internal_name = "1996_5400rpm", .zones = 16, .avg_spt = 135, .heads = 4, .rpm = 5400, .full_stroke_ms = 24, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 16 }, - { .name = "[Generic] 1997 (5400 RPM)", .internal_name = "1997_5400rpm", .zones = 16, .avg_spt = 185, .heads = 6, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 64, .max_multiple = 32 }, - { .name = "[Generic] 1998 (5400 RPM)", .internal_name = "1998_5400rpm", .zones = 16, .avg_spt = 300, .heads = 8, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 32 }, - { .name = "[Generic] 2000 (7200 RPM)", .internal_name = "2000_7200rpm", .zones = 16, .avg_spt = 350, .heads = 6, .rpm = 7200, .full_stroke_ms = 15, .track_seek_ms = 2, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 32 }, - { .name = "[PIO IDE] IBM WDA-L42", .internal_name = "WDAL42", .model = "WDA-L42", .zones = 1, .avg_spt = 85, .heads = 2, .rpm = 3600, .full_stroke_ms = 33, .track_seek_ms = 2.5, .rcache_num_seg = 1, .rcache_seg_size = 32, .max_multiple = 1 }, - { .name = "[PIO-2] IBM DSAA-3270", .internal_name = "DSAA3270", .model = "DSAA-3270", .zones = 8, .avg_spt = 268, .heads = 2, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 2.1, .rcache_num_seg = 3, .rcache_seg_size = 32, .max_multiple = 8, .version_ex = "25505120" }, - { .name = "[ATA-1] Conner CP3024", .internal_name = "CP3024", .model = "Conner Peripherals 20MB - CP3024", .zones = 1, .avg_spt = 33, .heads = 2, .rpm = 3500, .full_stroke_ms = 50, .track_seek_ms = 8, .rcache_num_seg = 1, .rcache_seg_size = 8, .max_multiple = 8 }, // Needed for GRiDcase 1520 to work - { .name = "[ATA-1] Conner CP3044", .internal_name = "CP3044", .model = "Conner Peripherals 40MB - CP3044", .zones = 1, .avg_spt = 40, .heads = 2, .rpm = 3500, .full_stroke_ms = 50, .track_seek_ms = 8, .rcache_num_seg = 1, .rcache_seg_size = 8, .max_multiple = 8 }, // Needed for GRiDcase 1520 to work - { .name = "[ATA-1] Conner CP3104", .internal_name = "CP3104", .model = "Conner Peripherals 104MB - CP3104", .zones = 1, .avg_spt = 33, .heads = 8, .rpm = 3500, .full_stroke_ms = 45, .track_seek_ms = 8, .rcache_num_seg = 4, .rcache_seg_size = 8, .max_multiple = 8 }, // Needed for GRiDcase 1520 to work - { .name = "[ATA-1] Conner CFS420A", .internal_name = "CFS420A", .model = "Conner Peripherals 420MB - CFS420A", .zones = 1, .avg_spt = 40, .heads = 2, .rpm = 3600, .full_stroke_ms = 33, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 32, .max_multiple = 8 }, - { .name = "[ATA-1] HP Kittyhawk", .internal_name = "C3014A", .model = "HP C3014A", .zones = 6, .avg_spt = 80, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 16, .max_multiple = 8 }, - { .name = "[ATA-1] IBM H3256-A3", .internal_name = "H3256A3", .model = "H3256-A3", .zones = 1, .avg_spt = 40, .heads = 2, .rpm = 3600, .full_stroke_ms = 32, .track_seek_ms = 4, .rcache_num_seg = 4, .rcache_seg_size = 96, .max_multiple = 8 }, - { .name = "[ATA-1] IBM H3342-A4", .internal_name = "H3342A4", .model = "H3342-A4", .zones = 1, .avg_spt = 40, .heads = 2, .rpm = 3600, .full_stroke_ms = 30, .track_seek_ms = 4, .rcache_num_seg = 4, .rcache_seg_size = 96, .max_multiple = 8 }, - { .name = "[ATA-1] Kalok KL343", .internal_name = "KL343", .model = "KALOK KL-343", .zones = 1, .avg_spt = 80, .heads = 6, .rpm = 3600, .full_stroke_ms = 50, .track_seek_ms = 2, .rcache_num_seg = 1, .rcache_seg_size = 8, .max_multiple = 8 }, - { .name = "[ATA-1] Kalok KL3100", .internal_name = "KL3100", .model = "KALOK KL-3100", .zones = 1, .avg_spt = 100, .heads = 6, .rpm = 3662, .full_stroke_ms = 50, .track_seek_ms = 2, .rcache_num_seg = 1, .rcache_seg_size = 32, .max_multiple = 8 }, - { .name = "[ATA-1] Maxtor 7060AT", .internal_name = "7060AT", .model = "Maxtor 7060 AT", .zones = 1, .avg_spt = 62, .heads = 2, .rpm = 3524, .full_stroke_ms = 30, .track_seek_ms = 3.6, .rcache_num_seg = 1, .rcache_seg_size = 64, .max_multiple = 8 }, - { .name = "[ATA-1] Maxtor 7131AT", .internal_name = "7131AT", .model = "Maxtor 7131 AT", .zones = 2, .avg_spt = 54, .heads = 2, .rpm = 3551, .full_stroke_ms = 27, .track_seek_ms = 4.5, .rcache_num_seg = 1, .rcache_seg_size = 64, .max_multiple = 8 }, - { .name = "[ATA-1] Maxtor 7213AT", .internal_name = "7213AT", .model = "Maxtor 7213 AT", .zones = 4, .avg_spt = 55, .heads = 4, .rpm = 3551, .full_stroke_ms = 28, .track_seek_ms = 6.5, .rcache_num_seg = 1, .rcache_seg_size = 64, .max_multiple = 8 }, - { .name = "[ATA-1] Maxtor 7245AT", .internal_name = "7245AT", .model = "Maxtor 7245 AT", .zones = 4, .avg_spt = 49, .heads = 4, .rpm = 3551, .full_stroke_ms = 27, .track_seek_ms = 4.4, .rcache_num_seg = 8, .rcache_seg_size = 64, .max_multiple = 8 }, - { .name = "[ATA-1] Quantum ProDrive LPS 105", .internal_name = "LPS105AT", .model = "QUANTUM PRODRIVE 105", .zones = 1, .avg_spt = 70, .heads = 2, .rpm = 3662, .full_stroke_ms = 45, .track_seek_ms = 5, .rcache_num_seg = 1, .rcache_seg_size = 64, .max_multiple = 8 }, - { .name = "[ATA-1] Quantum ProDrive LPS 120AT", .internal_name = "GM12A012", .model = "QUANTUM PRODRIVE 120AT", .zones = 1, .avg_spt = 50, .heads = 2, .rpm = 3605, .full_stroke_ms = 45, .track_seek_ms = 4, .rcache_num_seg = 1, .rcache_seg_size = 64, .max_multiple = 8 }, - { .name = "[ATA-1] Seagate ST3243A", .internal_name = "ST3243A", .model = "ST3243A", .zones = 1, .avg_spt = 40, .heads = 4, .rpm = 3811, .full_stroke_ms = 32, .track_seek_ms = 4, .rcache_num_seg = 4, .rcache_seg_size = 32, .max_multiple = 8 }, - { .name = "[ATA-1] Western Digital Caviar 140", .internal_name = "AC140", .model = "WDC AC140", .zones = 4, .avg_spt = 70, .heads = 2, .rpm = 3551, .full_stroke_ms = 28, .track_seek_ms = 6, .rcache_num_seg = 8, .rcache_seg_size = 8, .max_multiple = 8 }, - { .name = "[ATA-1] Western Digital Caviar 280", .internal_name = "AC280", .model = "WDC AC280", .zones = 4, .avg_spt = 70, .heads = 4, .rpm = 3595, .full_stroke_ms = 28, .track_seek_ms = 6, .rcache_num_seg = 8, .rcache_seg_size = 32, .max_multiple = 8 }, - { .name = "[ATA-1] Western Digital Caviar 1210", .internal_name = "AC1210", .model = "WDC AC1210F", .zones = 4, .avg_spt = 30, .heads = 2, .rpm = 3314, .full_stroke_ms = 33, .track_seek_ms = 4, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, - { .name = "[ATA-1] Western Digital Caviar 2120", .internal_name = "AC2120", .model = "WDC AC2120M", .zones = 4, .avg_spt = 40, .heads = 2, .rpm = 3605, .full_stroke_ms = 28, .track_seek_ms = 2.8, .rcache_num_seg = 8, .rcache_seg_size = 32, .max_multiple = 8 }, - { .name = "[ATA-2] IBM DBOA-2720", .internal_name = "DBOA2720", .model = "DBOA-2720", .zones = 2, .avg_spt = 135, .heads = 2, .rpm = 4000, .full_stroke_ms = 30, .track_seek_ms = 5, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 8 }, - { .name = "[ATA-2] IBM DeskStar 4 (DCAA-32880)", .internal_name = "DCAA32880", .model = "IBM-DCAA-32880", .zones = 8, .avg_spt = 185, .heads = 2, .rpm = 5400, .full_stroke_ms = 19, .track_seek_ms = 1.7, .rcache_num_seg = 4, .rcache_seg_size = 96, .max_multiple = 16 }, - { .name = "[ATA-2] IBM DeskStar 4 (DCAA-33610)", .internal_name = "DCAA33610", .model = "IBM-DCAA-33610", .zones = 8, .avg_spt = 185, .heads = 3, .rpm = 5400, .full_stroke_ms = 19, .track_seek_ms = 1.7, .rcache_num_seg = 4, .rcache_seg_size = 96, .max_multiple = 16 }, - { .name = "[ATA-2] IBM DeskStar 4 (DCAA-34330)", .internal_name = "DCAA34330", .model = "IBM-DCAA-34330", .zones = 8, .avg_spt = 185, .heads = 3, .rpm = 5400, .full_stroke_ms = 19, .track_seek_ms = 1.7, .rcache_num_seg = 4, .rcache_seg_size = 96, .max_multiple = 16 }, - { .name = "[ATA-2] Maxtor 7540AV", .internal_name = "7540AV", .model = "Maxtor 7540 AV", .zones = 2, .avg_spt = 120, .heads = 4, .rpm = 3551, .full_stroke_ms = 31, .track_seek_ms = 4.3, .rcache_num_seg = 4, .rcache_seg_size = 32, .max_multiple = 8 }, - { .name = "[ATA-2] Maxtor 7546AT", .internal_name = "7546AT", .model = "Maxtor 7546 AT", .zones = 2, .avg_spt = 100, .heads = 4, .rpm = 4500, .full_stroke_ms = 28, .track_seek_ms = 2.3, .rcache_num_seg = 4, .rcache_seg_size = 256, .max_multiple = 8 }, - { .name = "[ATA-2] Maxtor 7850AV", .internal_name = "7850AV", .model = "Maxtor 7850 AV", .zones = 4, .avg_spt = 120, .heads = 4, .rpm = 3551, .full_stroke_ms = 31, .track_seek_ms = 3.7, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 8 }, - { .name = "[ATA-2] Maxtor 71336AP", .internal_name = "71336AP", .model = "Maxtor 71336 AP", .zones = 4, .avg_spt = 105, .heads = 4, .rpm = 4480, .full_stroke_ms = 12, .track_seek_ms = 3.4, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-2] Quantum Bigfoot 1.2AT", .internal_name = "BF12A011", .model = "QUANTUM BIGFOOT BF1.2A", .zones = 2, .avg_spt = 155, .heads = 2, .rpm = 3600, .full_stroke_ms = 30, .track_seek_ms = 3.5, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-2] Quantum Bigfoot (CY4320A)", .internal_name = "CY4320A", .model = "QUANTUM BIGFOOT_CY4320A", .zones = 2, .avg_spt = 130, .heads = 2, .rpm = 4000, .full_stroke_ms = 29, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, // from Hardcore Windows NT Final Segment by Kugee - { .name = "[ATA-2] Quantum Fireball 640AT", .internal_name = "FB64A341", .model = "QUANTUM FIREBALL 640AT", .zones = 2, .avg_spt = 120, .heads = 2, .rpm = 5400, .full_stroke_ms = 24, .track_seek_ms = 3.1, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, - { .name = "[ATA-2] Quantum Fireball TM1080AT", .internal_name = "TM10A462", .model = "QUANTUM FIREBALL TM1.0A", .zones = 2, .avg_spt = 120, .heads = 2, .rpm = 4500, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 8 }, - { .name = "[ATA-2] Quantum Fireball TM1.2AT", .internal_name = "TM12A012", .model = "QUANTUM FIREBALL TM1.2A", .zones = 4, .avg_spt = 120, .heads = 2, .rpm = 4500, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 8 }, - { .name = "[ATA-2] Samsung PLS-31274A", .internal_name = "PLS31274A", .model = "SAMSUNG PLS-31274A", .zones = 4, .avg_spt = 110, .heads = 4, .rpm = 4500, .full_stroke_ms = 45, .track_seek_ms = 4.5, .rcache_num_seg = 4, .rcache_seg_size = 256, .max_multiple = 8 }, - { .name = "[ATA-2] Samsung Winner-1", .internal_name = "WNR31601A", .model = "SAMSUNG WNR-31601A", .zones = 8, .avg_spt = 110, .heads = 4, .rpm = 5400, .full_stroke_ms = 22, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-2] Seagate Medalist (ST3780A)", .internal_name = "ST3780A", .model = "ST3780A", .zones = 8, .avg_spt = 120, .heads = 4, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 3.5, .rcache_num_seg = 4, .rcache_seg_size = 256, .max_multiple = 16 }, - { .name = "[ATA-2] Seagate Medalist (ST31220A)", .internal_name = "ST31220A", .model = "ST31220A", .zones = 8, .avg_spt = 140, .heads = 6, .rpm = 4500, .full_stroke_ms = 27, .track_seek_ms = 3.5, .rcache_num_seg = 4, .rcache_seg_size = 256, .max_multiple = 16 }, - { .name = "[ATA-2] Seagate Medalist 210xe", .internal_name = "ST3250A", .model = "ST3250A", .zones = 4, .avg_spt = 148, .heads = 2, .rpm = 3811, .full_stroke_ms = 30, .track_seek_ms = 4.1, .rcache_num_seg = 8, .rcache_seg_size = 120, .max_multiple = 8 }, - { .name = "[ATA-2] Seagate Medalist 275xe", .internal_name = "ST3295A", .model = "ST3295A", .zones = 4, .avg_spt = 130, .heads = 2, .rpm = 3811, .full_stroke_ms = 30, .track_seek_ms = 3.4, .rcache_num_seg = 3, .rcache_seg_size = 120, .max_multiple = 8 }, - { .name = "[ATA-2] Seagate Medalist 545xe", .internal_name = "ST3660A", .model = "ST3660A", .zones = 4, .avg_spt = 130, .heads = 4, .rpm = 3811, .full_stroke_ms = 34, .track_seek_ms = 3.4, .rcache_num_seg = 8, .rcache_seg_size = 120, .max_multiple = 8 }, - { .name = "[ATA-2] Seagate Medalist 640xe", .internal_name = "ST3630A", .model = "ST3630A", .zones = 4, .avg_spt = 130, .heads = 4, .rpm = 3811, .full_stroke_ms = 34, .track_seek_ms = 3.5, .rcache_num_seg = 8, .rcache_seg_size = 120, .max_multiple = 8 }, - { .name = "[ATA-2] Seagate Medalist 850xe", .internal_name = "ST3850A", .model = "ST3850A", .zones = 8, .avg_spt = 150, .heads = 4, .rpm = 3811, .full_stroke_ms = 34, .track_seek_ms = 3.8, .rcache_num_seg = 8, .rcache_seg_size = 120, .max_multiple = 8 }, - { .name = "[ATA-2] Seagate Medalist 1270SL", .internal_name = "ST51270A", .model = "ST51270A", .zones = 8, .avg_spt = 205, .heads = 3, .rpm = 5736, .full_stroke_ms = 25, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-2] Seagate Medalist 3240", .internal_name = "ST33240A", .model = "ST33240A", .zones = 16, .avg_spt = 225, .heads = 8, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-2] Toshiba MK2101MAN (HDD2616)", .internal_name = "HDD2616", .model = "TOSHIBA MK2101MAN", .zones = 8, .avg_spt = 130, .heads = 10, .rpm = 4200, .full_stroke_ms = 36, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-2] Western Digital Caviar 2540", .internal_name = "AC2540", .model = "WDC AC2540H", .zones = 4, .avg_spt = 150, .heads = 2, .rpm = 4500, .full_stroke_ms = 12, .track_seek_ms = 4, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, - { .name = "[ATA-2] Western Digital Caviar 2850", .internal_name = "AC2850", .model = "WDC AC2850F", .zones = 4, .avg_spt = 130, .heads = 2, .rpm = 5200, .full_stroke_ms = 12, .track_seek_ms = 4, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 8 }, - { .name = "[ATA-2] Western Digital Caviar 11000", .internal_name = "AC11000", .model = "WDC AC11000H", .zones = 4, .avg_spt = 120, .heads = 2, .rpm = 5200, .full_stroke_ms = 12, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 8 }, - { .name = "[ATA-2] Western Digital Caviar 21200", .internal_name = "AC21200", .model = "WDC AC21200H", .zones = 4, .avg_spt = 110, .heads = 4, .rpm = 5200, .full_stroke_ms = 39, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, - { .name = "[ATA-2] Western Digital Caviar 21600", .internal_name = "AC21600", .model = "WDC AC21600H", .zones = 8, .avg_spt = 140, .heads = 4, .rpm = 5200, .full_stroke_ms = 30, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, - { .name = "[ATA-2] Western Digital Caviar 22000", .internal_name = "AC22000", .model = "WDC AC22000LA", .zones = 8, .avg_spt = 130, .heads = 3, .rpm = 5200, .full_stroke_ms = 33, .track_seek_ms = 3.5, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, - { .name = "[ATA-2] Western Digital Caviar 22100", .internal_name = "AC22100", .model = "WDC AC22100H", .zones = 8, .avg_spt = 140, .heads = 4, .rpm = 5200, .full_stroke_ms = 30, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-2] Western Digital Caviar 31200", .internal_name = "AC31200", .model = "WDC AC31200F", .zones = 8, .avg_spt = 210, .heads = 4, .rpm = 4500, .full_stroke_ms = 12, .track_seek_ms = 4, .rcache_num_seg = 8, .rcache_seg_size = 64, .max_multiple = 16 }, - { .name = "[ATA-3] Conner CFS1275A", .internal_name = "CFS1275A", .model = "Conner Peripherals 1275MB - CFS1275A", .zones = 4, .avg_spt = 130, .heads = 2, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 3.8, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 16 }, // Either ATA-2 or ATA-3 - { .name = "[ATA-3] Fujitsu MPA3017AT", .internal_name = "MPA3017AT", .model = "FUJITSU MPA3017AT", .zones = 5, .avg_spt = 195, .heads = 2, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-3] Fujitsu MPA3026AT", .internal_name = "MPA3026AT", .model = "FUJITSU MPA3026AT", .zones = 8, .avg_spt = 195, .heads = 3, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-3] Fujitsu MPA3035AT", .internal_name = "MPA3035AT", .model = "FUJITSU MPA3035AT", .zones = 11, .avg_spt = 195, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-3] Fujitsu MPA3043AT", .internal_name = "MPA3043AT", .model = "FUJITSU MPA3043AT", .zones = 15, .avg_spt = 195, .heads = 5, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-3] Fujitsu MPA3052AT", .internal_name = "MPA3052AT", .model = "FUJITSU MPA3052AT", .zones = 16, .avg_spt = 195, .heads = 6, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-3] Samsung Voyager 6", .internal_name = "SV0844A", .model = "SAMSUNG SV0844A", .zones = 8, .avg_spt = 205, .heads = 4, .rpm = 5400, .full_stroke_ms = 22, .track_seek_ms = 2, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-3] Samsung Winner 5X", .internal_name = "WU33205A", .model = "SAMSUNG WU33205A", .zones = 16, .avg_spt = 200, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-3] Seagate Medalist 636", .internal_name = "ST3636A", .model = "Seagate Technology 636MB - ST3636A", .zones = 2, .avg_spt = 130, .heads = 2, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 3.8, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 8 }, - { .name = "[ATA-3] Seagate Medalist 1082", .internal_name = "ST31082A", .model = "Seagate Technology 1082MB - ST31082A", .zones = 4, .avg_spt = 130, .heads = 3, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 3.8, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 8 }, - { .name = "[ATA-3] Seagate Medalist 1276", .internal_name = "ST31276A", .model = "Seagate Technology 1275MB - ST31276A", .zones = 4, .avg_spt = 130, .heads = 3, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 3.8, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 16 }, - { .name = "[ATA-3] Seagate Medalist 1720", .internal_name = "ST31720A", .model = "ST31720A", .zones = 4, .avg_spt = 120, .heads = 4, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 2, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-3] Seagate Medalist 2132", .internal_name = "ST32132A", .model = "ST32132A", .zones = 8, .avg_spt = 125, .heads = 6, .rpm = 4500, .full_stroke_ms = 30, .track_seek_ms = 2.3, .rcache_num_seg = 8, .rcache_seg_size = 120, .max_multiple = 16 }, - { .name = "[ATA-3] Western Digital Caviar 21700", .internal_name = "AC21700", .model = "WDC AC21700H", .zones = 8, .avg_spt = 185, .heads = 3, .rpm = 5200, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, // Apple Computer OEM only, not retail version - { .name = "[ATA-4] Fujitsu MPB3021AT", .internal_name = "MPB3021AT", .model = "FUJITSU MPB3021AT", .zones = 7, .avg_spt = 200, .heads = 3, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 256, .max_multiple = 16 }, - { .name = "[ATA-4] Fujitsu MPD3043AT", .internal_name = "MPD3043AT", .model = "FUJITSU MPD3043AT", .zones = 5, .avg_spt = 195, .heads = 2, .rpm = 5400, .full_stroke_ms = 29, .track_seek_ms = 1.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-4] Fujitsu MPD3064AT", .internal_name = "MPD3064AT", .model = "FUJITSU MPD3064AT", .zones = 7, .avg_spt = 195, .heads = 3, .rpm = 5400, .full_stroke_ms = 30, .track_seek_ms = 1.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-4] Fujitsu MPD3084AT", .internal_name = "MPD3084AT", .model = "FUJITSU MPD3084AT", .zones = 7, .avg_spt = 195, .heads = 4, .rpm = 5400, .full_stroke_ms = 19, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-4] Fujitsu MPE3064AT", .internal_name = "MPE3064AT", .model = "FUJITSU MPE3064AT", .zones = 7, .avg_spt = 295, .heads = 2, .rpm = 5400, .full_stroke_ms = 30, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-4] Maxtor DiamondMax 2160", .internal_name = "86480D6", .model = "Maxtor 86480D6", .zones = 8, .avg_spt = 197, .heads = 4, .rpm = 5200, .full_stroke_ms = 18, .track_seek_ms = 1, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-4] Maxtor DiamondMax 2880", .internal_name = "90432D3", .model = "Maxtor 90432D3", .zones = 16, .avg_spt = 190, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1, .rcache_num_seg = 8, .rcache_seg_size = 256, .max_multiple = 32 }, - { .name = "[ATA-4] Maxtor DiamondMax 3400", .internal_name = "90644D3", .model = "Maxtor 90644D3", .zones = 16, .avg_spt = 290, .heads = 3, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 0.9, .rcache_num_seg = 8, .rcache_seg_size = 256, .max_multiple = 32 }, - { .name = "[ATA-4] Maxtor DiamondMax 4320 (90432D2)", .internal_name = "90432D2", .model = "Maxtor 90432D2", .zones = 16, .avg_spt = 290, .heads = 2, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 0.9, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, - { .name = "[ATA-4] Maxtor DiamondMax 4320 (90845D4)", .internal_name = "90845D4", .model = "Maxtor 90845D4", .zones = 16, .avg_spt = 290, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 0.9, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, - { .name = "[ATA-4] Maxtor DiamondMax Plus 6800 (90683U2)", .internal_name = "90683U2", .model = "Maxtor 90683U2", .zones = 16, .avg_spt = 290, .heads = 2, .rpm = 7200, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, - { .name = "[ATA-4] Maxtor DiamondMax Plus 6800 (91024U3)", .internal_name = "91024U3", .model = "Maxtor 91024U3", .zones = 16, .avg_spt = 290, .heads = 3, .rpm = 7200, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, - { .name = "[ATA-4] Maxtor DiamondMax Plus 6800 (91366U4)", .internal_name = "91366U4", .model = "Maxtor 91366U4", .zones = 16, .avg_spt = 290, .heads = 4, .rpm = 7200, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, - { .name = "[ATA-4] Maxtor DiamondMax Plus 6800 (92049U6)", .internal_name = "92049U6", .model = "Maxtor 92049U6", .zones = 16, .avg_spt = 290, .heads = 6, .rpm = 7200, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, - { .name = "[ATA-4] Maxtor DiamondMax Plus 6800 (92732U8)", .internal_name = "92732U8", .model = "Maxtor 92732U8", .zones = 16, .avg_spt = 290, .heads = 8, .rpm = 7200, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, - { .name = "[ATA-4] Quantum Bigfoot TX4.3AT", .internal_name = "TX043A011", .model = "QUANTUM BIGFOOT TX4.3A", .zones = 2, .avg_spt = 220, .heads = 2, .rpm = 4000, .full_stroke_ms = 30, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 32 }, - { .name = "[ATA-4] Quantum Fireball ST3.2AT", .internal_name = "ST32A461", .model = "QUANTUM FIREBALL ST3.2A", .zones = 4, .avg_spt = 200, .heads = 4, .rpm = 5400, .full_stroke_ms = 21, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-4] Quantum Fireball SE4.3A", .internal_name = "SE43A011", .model = "QUANTUM FIREBALL SE4.3A", .zones = 2, .avg_spt = 200, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-4] Quantum Fireball SE6.4A", .internal_name = "SE64A011", .model = "QUANTUM FIREBALL SE6.4A", .zones = 3, .avg_spt = 200, .heads = 6, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-4] Quantum Fireball SE8.4A", .internal_name = "SE84A011", .model = "QUANTUM FIREBALL SE8.4A", .zones = 4, .avg_spt = 200, .heads = 8, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-4] Quantum Fireball EX12.7A", .internal_name = "EX12A012", .model = "QUANTUM FIREBALL EX12.7A", .zones = 4, .avg_spt = 200, .heads = 8, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16, .version_ex = "A0A.0D00" }, - { .name = "[ATA-4] Quantum Fireball LCT-08 (LA04A011)", .internal_name = "LA04A011", .model = "QUANTUM FIREBALLlct08 04", .zones = 8, .avg_spt = 280, .heads = 6, .rpm = 5400, .full_stroke_ms = 40, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16, .version_ex = "A05.0X00" }, - { .name = "[ATA-4] Seagate Medalist 2122", .internal_name = "ST32122A", .model = "ST32122A", .zones = 16, .avg_spt = 215, .heads = 2, .rpm = 4500, .full_stroke_ms = 23, .track_seek_ms = 3.8, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-4] Seagate Medalist 3321", .internal_name = "ST33221A", .model = "ST33221A", .zones = 16, .avg_spt = 210, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1.7, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-4] Seagate Medalist 4321", .internal_name = "ST34321A", .model = "ST34321A", .zones = 16, .avg_spt = 210, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2.2, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-4] Seagate Medalist 6531", .internal_name = "ST36531A", .model = "ST36531A", .zones = 16, .avg_spt = 215, .heads = 6, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1.7, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-4] Seagate Medalist 8420", .internal_name = "ST38420A", .model = "ST38420A", .zones = 16, .avg_spt = 290, .heads = 4, .rpm = 5400, .full_stroke_ms = 16, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-4] Seagate Medalist 13030", .internal_name = "ST313030A", .model = "ST313030A", .zones = 16, .avg_spt = 290, .heads = 6, .rpm = 5400, .full_stroke_ms = 16, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-4] Seagate Medalist 17240", .internal_name = "ST317240A", .model = "ST317240A", .zones = 16, .avg_spt = 290, .heads = 8, .rpm = 5400, .full_stroke_ms = 16, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-4] Toshiba MK4006MAV", .internal_name = "MK4006MAV", .model = "TOSHIBA MK4006MAV", .zones = 8, .avg_spt = 230, .heads = 6, .rpm = 4200, .full_stroke_ms = 25, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-4] Western Digital Caviar 14300", .internal_name = "AC14300", .model = "WDC AC14300RT", .zones = 16, .avg_spt = 195, .heads = 2, .rpm = 5400, .full_stroke_ms = 21, .track_seek_ms = 5.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-4] Western Digital Caviar 23200", .internal_name = "AC23200", .model = "WDC AC23200LB", .zones = 16, .avg_spt = 210, .heads = 4, .rpm = 5400, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 256, .max_multiple = 32 }, - { .name = "[ATA-4] Western Digital Caviar 26400", .internal_name = "AC26400", .model = "WDC AC26400RN", .zones = 16, .avg_spt = 295, .heads = 5, .rpm = 5400, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-4] Western Digital Caviar 33200", .internal_name = "AC33200", .model = "WDC AC33200LA", .zones = 16, .avg_spt = 310, .heads = 5, .rpm = 5200, .full_stroke_ms = 40, .track_seek_ms = 3, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, - { .name = "[ATA-4] Western Digital Caviar 35100", .internal_name = "AC35100", .model = "WDC AC35100L", .zones = 16, .avg_spt = 315, .heads = 5, .rpm = 5400, .full_stroke_ms = 40, .track_seek_ms = 3, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32, .version_ex = "09.09M08" }, - { .name = "[ATA-5] IBM Travelstar 6GN", .internal_name = "DARA206000", .model = "IBM-DARA-206000", .zones = 12, .avg_spt = 292, .heads = 2, .rpm = 4200, .full_stroke_ms = 31, .track_seek_ms = 4, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] IBM Travelstar 9GN", .internal_name = "DARA209000", .model = "IBM-DARA-209000", .zones = 12, .avg_spt = 292, .heads = 3, .rpm = 4200, .full_stroke_ms = 31, .track_seek_ms = 4, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] IBM/Hitachi Travelstar 12GN", .internal_name = "DARA212000", .model = "IBM-DARA-212000", .zones = 12, .avg_spt = 292, .heads = 4, .rpm = 4200, .full_stroke_ms = 31, .track_seek_ms = 4, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, // Either Hitachi or IBM OEM - { .name = "[ATA-5] Maxtor DiamondMax VL 17", .internal_name = "90871U2", .model = "Maxtor 90871U2", .zones = 16, .avg_spt = 290, .heads = 3, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 0.9, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, - { .name = "[ATA-5] Maxtor DiamondMax VL 20 (91021U2)", .internal_name = "91021U2", .model = "Maxtor 91021U2", .zones = 16, .avg_spt = 295, .heads = 2, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] Maxtor DiamondMax VL 20 (91531U3)", .internal_name = "91531U3", .model = "Maxtor 91531U3", .zones = 16, .avg_spt = 295, .heads = 3, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] Maxtor DiamondMax VL 20 (92041U4)", .internal_name = "92041U4", .model = "Maxtor 92041U4", .zones = 16, .avg_spt = 295, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] Quantum Fireball EX3.2A", .internal_name = "EX32A012", .model = "QUANTUM FIREBALL EX3.2A", .zones = 1, .avg_spt = 210, .heads = 2, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-5] Quantum Fireball EX5.1A", .internal_name = "EX51A012", .model = "QUANTUM FIREBALL EX5.1A", .zones = 2, .avg_spt = 210, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-5] Quantum Fireball EX6.4A", .internal_name = "EX64A012", .model = "QUANTUM FIREBALL EX6.4A", .zones = 2, .avg_spt = 210, .heads = 4, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-5] Quantum Fireball EX10.2A", .internal_name = "EX10A011", .model = "QUANTUM FIREBALL EX10.2A", .zones = 3, .avg_spt = 210, .heads = 6, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-5] Quantum Fireball EX12.7A", .internal_name = "EX12A011", .model = "QUANTUM FIREBALL EX12.7A", .zones = 4, .avg_spt = 210, .heads = 8, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-5] Quantum Fireball CR4.3A", .internal_name = "CR43A013", .model = "QUANTUM FIREBALL CR4.3A", .zones = 2, .avg_spt = 310, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-5] Quantum Fireball CR6.4A", .internal_name = "CR64A011", .model = "QUANTUM FIREBALL CR6.4A", .zones = 2, .avg_spt = 310, .heads = 4, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-5] Quantum Fireball CR8.4A", .internal_name = "CR84A011", .model = "QUANTUM FIREBALL CR8.4A", .zones = 3, .avg_spt = 310, .heads = 6, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-5] Quantum Fireball CR13.0A", .internal_name = "CR13A011", .model = "QUANTUM FIREBALL CR13.0A", .zones = 4, .avg_spt = 310, .heads = 8, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-5] Samsung SpinPoint V6800 (SV0682D)", .internal_name = "SV0682D", .model = "SAMSUNG SV0682D", .zones = 8, .avg_spt = 295, .heads = 2, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] Samsung SpinPoint V6800 (SV1023D)", .internal_name = "SV1023D", .model = "SAMSUNG SV1023D", .zones = 8, .avg_spt = 295, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] Samsung SpinPoint V6800 (SV1364D)", .internal_name = "SV1364D", .model = "SAMSUNG SV1364D", .zones = 8, .avg_spt = 295, .heads = 4, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] Samsung SpinPoint V6800 (SV1705D)", .internal_name = "SV1705D", .model = "SAMSUNG SV1705D", .zones = 8, .avg_spt = 295, .heads = 5, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] Samsung SpinPoint V6800 (SV2046D)", .internal_name = "SV2046D", .model = "SAMSUNG SV2046D", .zones = 8, .avg_spt = 295, .heads = 6, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] Seagate U8 - 4.3gb", .internal_name = "ST34313A", .model = "ST34313A", .zones = 16, .avg_spt = 289, .heads = 1, .rpm = 5400, .full_stroke_ms = 25, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] Seagate U8 - 8.4gb", .internal_name = "ST38410A", .model = "ST38410A", .zones = 16, .avg_spt = 289, .heads = 2, .rpm = 5400, .full_stroke_ms = 25, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] Seagate U8 - 13gb", .internal_name = "ST313021A", .model = "ST313021A", .zones = 16, .avg_spt = 289, .heads = 4, .rpm = 5400, .full_stroke_ms = 25, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] Seagate U8 - 17.2gb", .internal_name = "ST317221A", .model = "ST317221A", .zones = 16, .avg_spt = 289, .heads = 3, .rpm = 5400, .full_stroke_ms = 25, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] Western Digital Caviar 102AA", .internal_name = "WD102AA", .model = "WDC WD102AA-00ANA0", .zones = 16, .avg_spt = 295, .heads = 8, .rpm = 5400, .full_stroke_ms = 12, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, - { .name = "[ATA-5] Western Digital Expert", .internal_name = "WD135BA", .model = "WDC WD135BA-60AK", .zones = 16, .avg_spt = 350, .heads = 6, .rpm = 7200, .full_stroke_ms = 15, .track_seek_ms = 2, .rcache_num_seg = 16, .rcache_seg_size = 1920, .max_multiple = 32 }, + { .name = "[Generic] RAM Disk (max. speed)", .internal_name = "ramdisk", .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 32 }, + { .name = "[Generic] 1989 (3500 RPM)", .internal_name = "1989_3500rpm", .zones = 1, .avg_spt = 35, .heads = 2, .rpm = 3500, .full_stroke_ms = 40, .track_seek_ms = 8, .rcache_num_seg = 1, .rcache_seg_size = 16, .max_multiple = 8 }, + { .name = "[Generic] 1992 (3600 RPM)", .internal_name = "1992_3600rpm", .zones = 1, .avg_spt = 45, .heads = 2, .rpm = 3600, .full_stroke_ms = 30, .track_seek_ms = 6, .rcache_num_seg = 4, .rcache_seg_size = 16, .max_multiple = 8 }, + { .name = "[Generic] 1994 (4500 RPM)", .internal_name = "1994_4500rpm", .zones = 8, .avg_spt = 80, .heads = 4, .rpm = 4500, .full_stroke_ms = 26, .track_seek_ms = 5, .rcache_num_seg = 4, .rcache_seg_size = 32, .max_multiple = 16 }, + { .name = "[Generic] 1996 (5400 RPM)", .internal_name = "1996_5400rpm", .zones = 16, .avg_spt = 135, .heads = 4, .rpm = 5400, .full_stroke_ms = 24, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 16 }, + { .name = "[Generic] 1997 (5400 RPM)", .internal_name = "1997_5400rpm", .zones = 16, .avg_spt = 185, .heads = 6, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 64, .max_multiple = 32 }, + { .name = "[Generic] 1998 (5400 RPM)", .internal_name = "1998_5400rpm", .zones = 16, .avg_spt = 300, .heads = 8, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 32 }, + { .name = "[Generic] 2000 (7200 RPM)", .internal_name = "2000_7200rpm", .zones = 16, .avg_spt = 350, .heads = 6, .rpm = 7200, .full_stroke_ms = 15, .track_seek_ms = 2, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 32 }, + { .name = "[PIO IDE] IBM WDA-L42", .internal_name = "WDAL42", .model = "WDA-L42", .zones = 1, .avg_spt = 85, .heads = 2, .rpm = 3600, .full_stroke_ms = 33, .track_seek_ms = 2.5, .rcache_num_seg = 1, .rcache_seg_size = 32, .max_multiple = 1 }, + { .name = "[PIO-2] IBM DSAA-3270", .internal_name = "DSAA3270", .model = "DSAA-3270", .version = "25505120", .zones = 8, .avg_spt = 268, .heads = 2, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 2.1, .rcache_num_seg = 3, .rcache_seg_size = 32, .max_multiple = 8 }, + { .name = "[ATA-1] Conner CP3024", .internal_name = "CP3024", .model = "Conner Peripherals 20MB - CP3024", .zones = 1, .avg_spt = 33, .heads = 2, .rpm = 3500, .full_stroke_ms = 50, .track_seek_ms = 8, .rcache_num_seg = 1, .rcache_seg_size = 8, .max_multiple = 8 }, // Needed for GRiDcase 1520 to work + { .name = "[ATA-1] Conner CP3044", .internal_name = "CP3044", .model = "Conner Peripherals 40MB - CP3044", .zones = 1, .avg_spt = 40, .heads = 2, .rpm = 3500, .full_stroke_ms = 50, .track_seek_ms = 8, .rcache_num_seg = 1, .rcache_seg_size = 8, .max_multiple = 8 }, // Needed for GRiDcase 1520 to work + { .name = "[ATA-1] Conner CP3104", .internal_name = "CP3104", .model = "Conner Peripherals 104MB - CP3104", .zones = 1, .avg_spt = 33, .heads = 8, .rpm = 3500, .full_stroke_ms = 45, .track_seek_ms = 8, .rcache_num_seg = 4, .rcache_seg_size = 8, .max_multiple = 8 }, // Needed for GRiDcase 1520 to work + { .name = "[ATA-1] Conner CFS420A", .internal_name = "CFS420A", .model = "Conner Peripherals 420MB - CFS420A", .zones = 1, .avg_spt = 40, .heads = 2, .rpm = 3600, .full_stroke_ms = 33, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 32, .max_multiple = 8 }, + { .name = "[ATA-1] HP Kittyhawk", .internal_name = "C3014A", .model = "HP C3014A", .zones = 6, .avg_spt = 80, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 16, .max_multiple = 8 }, + { .name = "[ATA-1] IBM H3256-A3", .internal_name = "H3256A3", .model = "H3256-A3", .zones = 1, .avg_spt = 40, .heads = 2, .rpm = 3600, .full_stroke_ms = 32, .track_seek_ms = 4, .rcache_num_seg = 4, .rcache_seg_size = 96, .max_multiple = 8 }, + { .name = "[ATA-1] IBM H3342-A4", .internal_name = "H3342A4", .model = "H3342-A4", .zones = 1, .avg_spt = 40, .heads = 2, .rpm = 3600, .full_stroke_ms = 30, .track_seek_ms = 4, .rcache_num_seg = 4, .rcache_seg_size = 96, .max_multiple = 8 }, + { .name = "[ATA-1] Kalok KL343", .internal_name = "KL343", .model = "KALOK KL-343", .zones = 1, .avg_spt = 80, .heads = 6, .rpm = 3600, .full_stroke_ms = 50, .track_seek_ms = 2, .rcache_num_seg = 1, .rcache_seg_size = 8, .max_multiple = 8 }, + { .name = "[ATA-1] Kalok KL3100", .internal_name = "KL3100", .model = "KALOK KL-3100", .zones = 1, .avg_spt = 100, .heads = 6, .rpm = 3662, .full_stroke_ms = 50, .track_seek_ms = 2, .rcache_num_seg = 1, .rcache_seg_size = 32, .max_multiple = 8 }, + { .name = "[ATA-1] Maxtor 7060AT", .internal_name = "7060AT", .model = "Maxtor 7060 AT", .zones = 1, .avg_spt = 62, .heads = 2, .rpm = 3524, .full_stroke_ms = 30, .track_seek_ms = 3.6, .rcache_num_seg = 1, .rcache_seg_size = 64, .max_multiple = 8 }, + { .name = "[ATA-1] Maxtor 7131AT", .internal_name = "7131AT", .model = "Maxtor 7131 AT", .zones = 2, .avg_spt = 54, .heads = 2, .rpm = 3551, .full_stroke_ms = 27, .track_seek_ms = 4.5, .rcache_num_seg = 1, .rcache_seg_size = 64, .max_multiple = 8 }, + { .name = "[ATA-1] Maxtor 7213AT", .internal_name = "7213AT", .model = "Maxtor 7213 AT", .zones = 4, .avg_spt = 55, .heads = 4, .rpm = 3551, .full_stroke_ms = 28, .track_seek_ms = 6.5, .rcache_num_seg = 1, .rcache_seg_size = 64, .max_multiple = 8 }, + { .name = "[ATA-1] Maxtor 7245AT", .internal_name = "7245AT", .model = "Maxtor 7245 AT", .zones = 4, .avg_spt = 49, .heads = 4, .rpm = 3551, .full_stroke_ms = 27, .track_seek_ms = 4.4, .rcache_num_seg = 8, .rcache_seg_size = 64, .max_multiple = 8 }, + { .name = "[ATA-1] Quantum ProDrive LPS 105", .internal_name = "LPS105AT", .model = "QUANTUM PRODRIVE 105", .zones = 1, .avg_spt = 70, .heads = 2, .rpm = 3662, .full_stroke_ms = 45, .track_seek_ms = 5, .rcache_num_seg = 1, .rcache_seg_size = 64, .max_multiple = 8 }, + { .name = "[ATA-1] Quantum ProDrive LPS 120AT", .internal_name = "GM12A012", .model = "QUANTUM PRODRIVE 120AT", .zones = 1, .avg_spt = 50, .heads = 2, .rpm = 3605, .full_stroke_ms = 45, .track_seek_ms = 4, .rcache_num_seg = 1, .rcache_seg_size = 64, .max_multiple = 8 }, + { .name = "[ATA-1] Seagate ST3243A", .internal_name = "ST3243A", .model = "ST3243A", .zones = 1, .avg_spt = 40, .heads = 4, .rpm = 3811, .full_stroke_ms = 32, .track_seek_ms = 4, .rcache_num_seg = 4, .rcache_seg_size = 32, .max_multiple = 8 }, + { .name = "[ATA-1] Western Digital Caviar 140", .internal_name = "AC140", .model = "WDC AC140", .zones = 4, .avg_spt = 70, .heads = 2, .rpm = 3551, .full_stroke_ms = 28, .track_seek_ms = 6, .rcache_num_seg = 8, .rcache_seg_size = 8, .max_multiple = 8 }, + { .name = "[ATA-1] Western Digital Caviar 280", .internal_name = "AC280", .model = "WDC AC280", .zones = 4, .avg_spt = 70, .heads = 4, .rpm = 3595, .full_stroke_ms = 28, .track_seek_ms = 6, .rcache_num_seg = 8, .rcache_seg_size = 32, .max_multiple = 8 }, + { .name = "[ATA-1] Western Digital Caviar 1210", .internal_name = "AC1210", .model = "WDC AC1210F", .zones = 4, .avg_spt = 30, .heads = 2, .rpm = 3314, .full_stroke_ms = 33, .track_seek_ms = 4, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, + { .name = "[ATA-1] Western Digital Caviar 2120", .internal_name = "AC2120", .model = "WDC AC2120M", .zones = 4, .avg_spt = 40, .heads = 2, .rpm = 3605, .full_stroke_ms = 28, .track_seek_ms = 2.8, .rcache_num_seg = 8, .rcache_seg_size = 32, .max_multiple = 8 }, + { .name = "[ATA-2] IBM DBOA-2720", .internal_name = "DBOA2720", .model = "DBOA-2720", .zones = 2, .avg_spt = 135, .heads = 2, .rpm = 4000, .full_stroke_ms = 30, .track_seek_ms = 5, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 8 }, + { .name = "[ATA-2] IBM DeskStar 4 (DCAA-32880)", .internal_name = "DCAA32880", .model = "IBM-DCAA-32880", .zones = 8, .avg_spt = 185, .heads = 2, .rpm = 5400, .full_stroke_ms = 19, .track_seek_ms = 1.7, .rcache_num_seg = 4, .rcache_seg_size = 96, .max_multiple = 16 }, + { .name = "[ATA-2] IBM DeskStar 4 (DCAA-33610)", .internal_name = "DCAA33610", .model = "IBM-DCAA-33610", .zones = 8, .avg_spt = 185, .heads = 3, .rpm = 5400, .full_stroke_ms = 19, .track_seek_ms = 1.7, .rcache_num_seg = 4, .rcache_seg_size = 96, .max_multiple = 16 }, + { .name = "[ATA-2] IBM DeskStar 4 (DCAA-34330)", .internal_name = "DCAA34330", .model = "IBM-DCAA-34330", .zones = 8, .avg_spt = 185, .heads = 3, .rpm = 5400, .full_stroke_ms = 19, .track_seek_ms = 1.7, .rcache_num_seg = 4, .rcache_seg_size = 96, .max_multiple = 16 }, + { .name = "[ATA-2] Maxtor 7540AV", .internal_name = "7540AV", .model = "Maxtor 7540 AV", .zones = 2, .avg_spt = 120, .heads = 4, .rpm = 3551, .full_stroke_ms = 31, .track_seek_ms = 4.3, .rcache_num_seg = 4, .rcache_seg_size = 32, .max_multiple = 8 }, + { .name = "[ATA-2] Maxtor 7546AT", .internal_name = "7546AT", .model = "Maxtor 7546 AT", .zones = 2, .avg_spt = 100, .heads = 4, .rpm = 4500, .full_stroke_ms = 28, .track_seek_ms = 2.3, .rcache_num_seg = 4, .rcache_seg_size = 256, .max_multiple = 8 }, + { .name = "[ATA-2] Maxtor 7850AV", .internal_name = "7850AV", .model = "Maxtor 7850 AV", .zones = 4, .avg_spt = 120, .heads = 4, .rpm = 3551, .full_stroke_ms = 31, .track_seek_ms = 3.7, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 8 }, + { .name = "[ATA-2] Maxtor 71336AP", .internal_name = "71336AP", .model = "Maxtor 71336 AP", .zones = 4, .avg_spt = 105, .heads = 4, .rpm = 4480, .full_stroke_ms = 12, .track_seek_ms = 3.4, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-2] Quantum Bigfoot 1.2AT", .internal_name = "BF12A011", .model = "QUANTUM BIGFOOT BF1.2A", .zones = 2, .avg_spt = 155, .heads = 2, .rpm = 3600, .full_stroke_ms = 30, .track_seek_ms = 3.5, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-2] Quantum Bigfoot (CY4320A)", .internal_name = "CY4320A", .model = "QUANTUM BIGFOOT_CY4320A", .zones = 2, .avg_spt = 130, .heads = 2, .rpm = 4000, .full_stroke_ms = 29, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, // from Hardcore Windows NT Final Segment by Kugee + { .name = "[ATA-2] Quantum Fireball 640AT", .internal_name = "FB64A341", .model = "QUANTUM FIREBALL 640AT", .zones = 2, .avg_spt = 120, .heads = 2, .rpm = 5400, .full_stroke_ms = 24, .track_seek_ms = 3.1, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, + { .name = "[ATA-2] Quantum Fireball TM1080AT", .internal_name = "TM10A462", .model = "QUANTUM FIREBALL TM1.0A", .zones = 2, .avg_spt = 120, .heads = 2, .rpm = 4500, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 8 }, + { .name = "[ATA-2] Quantum Fireball TM1.2AT", .internal_name = "TM12A012", .model = "QUANTUM FIREBALL TM1.2A", .zones = 4, .avg_spt = 120, .heads = 2, .rpm = 4500, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 8 }, + { .name = "[ATA-2] Samsung PLS-31274A", .internal_name = "PLS31274A", .model = "SAMSUNG PLS-31274A", .zones = 4, .avg_spt = 110, .heads = 4, .rpm = 4500, .full_stroke_ms = 45, .track_seek_ms = 4.5, .rcache_num_seg = 4, .rcache_seg_size = 256, .max_multiple = 8 }, + { .name = "[ATA-2] Samsung Winner-1", .internal_name = "WNR31601A", .model = "SAMSUNG WNR-31601A", .zones = 8, .avg_spt = 110, .heads = 4, .rpm = 5400, .full_stroke_ms = 22, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-2] Seagate Medalist (ST3780A)", .internal_name = "ST3780A", .model = "ST3780A", .zones = 8, .avg_spt = 120, .heads = 4, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 3.5, .rcache_num_seg = 4, .rcache_seg_size = 256, .max_multiple = 16 }, + { .name = "[ATA-2] Seagate Medalist (ST31220A)", .internal_name = "ST31220A", .model = "ST31220A", .zones = 8, .avg_spt = 140, .heads = 6, .rpm = 4500, .full_stroke_ms = 27, .track_seek_ms = 3.5, .rcache_num_seg = 4, .rcache_seg_size = 256, .max_multiple = 16 }, + { .name = "[ATA-2] Seagate Medalist 210xe", .internal_name = "ST3250A", .model = "ST3250A", .zones = 4, .avg_spt = 148, .heads = 2, .rpm = 3811, .full_stroke_ms = 30, .track_seek_ms = 4.1, .rcache_num_seg = 8, .rcache_seg_size = 120, .max_multiple = 8 }, + { .name = "[ATA-2] Seagate Medalist 275xe", .internal_name = "ST3295A", .model = "ST3295A", .zones = 4, .avg_spt = 130, .heads = 2, .rpm = 3811, .full_stroke_ms = 30, .track_seek_ms = 3.4, .rcache_num_seg = 3, .rcache_seg_size = 120, .max_multiple = 8 }, + { .name = "[ATA-2] Seagate Medalist 545xe", .internal_name = "ST3660A", .model = "ST3660A", .zones = 4, .avg_spt = 130, .heads = 4, .rpm = 3811, .full_stroke_ms = 34, .track_seek_ms = 3.4, .rcache_num_seg = 8, .rcache_seg_size = 120, .max_multiple = 8 }, + { .name = "[ATA-2] Seagate Medalist 640xe", .internal_name = "ST3630A", .model = "ST3630A", .zones = 4, .avg_spt = 130, .heads = 4, .rpm = 3811, .full_stroke_ms = 34, .track_seek_ms = 3.5, .rcache_num_seg = 8, .rcache_seg_size = 120, .max_multiple = 8 }, + { .name = "[ATA-2] Seagate Medalist 850xe", .internal_name = "ST3850A", .model = "ST3850A", .zones = 8, .avg_spt = 150, .heads = 4, .rpm = 3811, .full_stroke_ms = 34, .track_seek_ms = 3.8, .rcache_num_seg = 8, .rcache_seg_size = 120, .max_multiple = 8 }, + { .name = "[ATA-2] Seagate Medalist 1270SL", .internal_name = "ST51270A", .model = "ST51270A", .zones = 8, .avg_spt = 205, .heads = 3, .rpm = 5736, .full_stroke_ms = 25, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-2] Seagate Medalist 3240", .internal_name = "ST33240A", .model = "ST33240A", .zones = 16, .avg_spt = 225, .heads = 8, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-2] Toshiba MK2101MAN (HDD2616)", .internal_name = "HDD2616", .model = "TOSHIBA MK2101MAN", .zones = 8, .avg_spt = 130, .heads = 10, .rpm = 4200, .full_stroke_ms = 36, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-2] Western Digital Caviar 2540", .internal_name = "AC2540", .model = "WDC AC2540H", .zones = 4, .avg_spt = 150, .heads = 2, .rpm = 4500, .full_stroke_ms = 12, .track_seek_ms = 4, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, + { .name = "[ATA-2] Western Digital Caviar 2850", .internal_name = "AC2850", .model = "WDC AC2850F", .zones = 4, .avg_spt = 130, .heads = 2, .rpm = 5200, .full_stroke_ms = 12, .track_seek_ms = 4, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 8 }, + { .name = "[ATA-2] Western Digital Caviar 11000", .internal_name = "AC11000", .model = "WDC AC11000H", .zones = 4, .avg_spt = 120, .heads = 2, .rpm = 5200, .full_stroke_ms = 12, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 8 }, + { .name = "[ATA-2] Western Digital Caviar 21200", .internal_name = "AC21200", .model = "WDC AC21200H", .zones = 4, .avg_spt = 110, .heads = 4, .rpm = 5200, .full_stroke_ms = 39, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, + { .name = "[ATA-2] Western Digital Caviar 21600", .internal_name = "AC21600", .model = "WDC AC21600H", .zones = 8, .avg_spt = 140, .heads = 4, .rpm = 5200, .full_stroke_ms = 30, .track_seek_ms = 3, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, + { .name = "[ATA-2] Western Digital Caviar 22000", .internal_name = "AC22000", .model = "WDC AC22000LA", .zones = 8, .avg_spt = 130, .heads = 3, .rpm = 5200, .full_stroke_ms = 33, .track_seek_ms = 3.5, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, + { .name = "[ATA-2] Western Digital Caviar 22100", .internal_name = "AC22100", .model = "WDC AC22100H", .zones = 8, .avg_spt = 140, .heads = 4, .rpm = 5200, .full_stroke_ms = 30, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-2] Western Digital Caviar 31200", .internal_name = "AC31200", .model = "WDC AC31200F", .zones = 8, .avg_spt = 210, .heads = 4, .rpm = 4500, .full_stroke_ms = 12, .track_seek_ms = 4, .rcache_num_seg = 8, .rcache_seg_size = 64, .max_multiple = 16 }, + { .name = "[ATA-3] Conner CFS1275A", .internal_name = "CFS1275A", .model = "Conner Peripherals 1275MB - CFS1275A", .zones = 4, .avg_spt = 130, .heads = 2, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 3.8, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 16 }, // Either ATA-2 or ATA-3 + { .name = "[ATA-3] Fujitsu MPA3017AT", .internal_name = "MPA3017AT", .model = "FUJITSU MPA3017AT", .zones = 5, .avg_spt = 195, .heads = 2, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-3] Fujitsu MPA3026AT", .internal_name = "MPA3026AT", .model = "FUJITSU MPA3026AT", .zones = 8, .avg_spt = 195, .heads = 3, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-3] Fujitsu MPA3035AT", .internal_name = "MPA3035AT", .model = "FUJITSU MPA3035AT", .zones = 11, .avg_spt = 195, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-3] Fujitsu MPA3043AT", .internal_name = "MPA3043AT", .model = "FUJITSU MPA3043AT", .zones = 15, .avg_spt = 195, .heads = 5, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-3] Fujitsu MPA3052AT", .internal_name = "MPA3052AT", .model = "FUJITSU MPA3052AT", .zones = 16, .avg_spt = 195, .heads = 6, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3.2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-3] Samsung Voyager 6", .internal_name = "SV0844A", .model = "SAMSUNG SV0844A", .zones = 8, .avg_spt = 205, .heads = 4, .rpm = 5400, .full_stroke_ms = 22, .track_seek_ms = 2, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-3] Samsung Winner 5X", .internal_name = "WU33205A", .model = "SAMSUNG WU33205A", .zones = 6, .avg_spt = 200, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-3] Seagate Medalist 636", .internal_name = "ST3636A", .model = "Seagate Technology 636MB - ST3636A", .zones = 2, .avg_spt = 130, .heads = 2, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 3.8, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 8 }, + { .name = "[ATA-3] Seagate Medalist 1082", .internal_name = "ST31082A", .model = "Seagate Technology 1082MB - ST31082A", .zones = 4, .avg_spt = 130, .heads = 3, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 3.8, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 8 }, + { .name = "[ATA-3] Seagate Medalist 1276", .internal_name = "ST31276A", .model = "Seagate Technology 1275MB - ST31276A", .zones = 4, .avg_spt = 130, .heads = 3, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 3.8, .rcache_num_seg = 4, .rcache_seg_size = 64, .max_multiple = 16 }, + { .name = "[ATA-3] Seagate Medalist 1720", .internal_name = "ST31720A", .model = "ST31720A", .zones = 4, .avg_spt = 120, .heads = 4, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 2, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-3] Seagate Medalist 2132", .internal_name = "ST32132A", .model = "ST32132A", .zones = 8, .avg_spt = 125, .heads = 6, .rpm = 4500, .full_stroke_ms = 30, .track_seek_ms = 2.3, .rcache_num_seg = 8, .rcache_seg_size = 120, .max_multiple = 16 }, + { .name = "[ATA-3] Western Digital Caviar 21700", .internal_name = "AC21700", .model = "WDC AC21700H", .zones = 8, .avg_spt = 185, .heads = 3, .rpm = 5200, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, // Apple Computer OEM only, not retail version + { .name = "[ATA-4] Fujitsu MPB3021AT", .internal_name = "MPB3021AT", .model = "FUJITSU MPB3021AT", .zones = 7, .avg_spt = 200, .heads = 3, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 256, .max_multiple = 16 }, + { .name = "[ATA-4] Fujitsu MPD3043AT", .internal_name = "MPD3043AT", .model = "FUJITSU MPD3043AT", .zones = 5, .avg_spt = 195, .heads = 2, .rpm = 5400, .full_stroke_ms = 29, .track_seek_ms = 1.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-4] Fujitsu MPD3064AT", .internal_name = "MPD3064AT", .model = "FUJITSU MPD3064AT", .zones = 7, .avg_spt = 195, .heads = 3, .rpm = 5400, .full_stroke_ms = 30, .track_seek_ms = 1.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-4] Fujitsu MPD3084AT", .internal_name = "MPD3084AT", .model = "FUJITSU MPD3084AT", .zones = 7, .avg_spt = 195, .heads = 4, .rpm = 5400, .full_stroke_ms = 19, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-4] Fujitsu MPE3064AT", .internal_name = "MPE3064AT", .model = "FUJITSU MPE3064AT", .zones = 7, .avg_spt = 295, .heads = 2, .rpm = 5400, .full_stroke_ms = 30, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-4] Maxtor DiamondMax 2160", .internal_name = "86480D6", .model = "Maxtor 86480D6", .zones = 8, .avg_spt = 197, .heads = 4, .rpm = 5200, .full_stroke_ms = 18, .track_seek_ms = 1, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-4] Maxtor DiamondMax 2880", .internal_name = "90432D3", .model = "Maxtor 90432D3", .zones = 16, .avg_spt = 190, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1, .rcache_num_seg = 8, .rcache_seg_size = 256, .max_multiple = 32 }, + { .name = "[ATA-4] Maxtor DiamondMax 3400", .internal_name = "90644D3", .model = "Maxtor 90644D3", .zones = 16, .avg_spt = 290, .heads = 3, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 0.9, .rcache_num_seg = 8, .rcache_seg_size = 256, .max_multiple = 32 }, + { .name = "[ATA-4] Maxtor DiamondMax 4320 (90432D2)", .internal_name = "90432D2", .model = "Maxtor 90432D2", .zones = 16, .avg_spt = 290, .heads = 2, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 0.9, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, + { .name = "[ATA-4] Maxtor DiamondMax 4320 (90845D4)", .internal_name = "90845D4", .model = "Maxtor 90845D4", .zones = 16, .avg_spt = 290, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 0.9, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, + { .name = "[ATA-4] Maxtor DiamondMax Plus 6800 (90683U2)", .internal_name = "90683U2", .model = "Maxtor 90683U2", .zones = 16, .avg_spt = 290, .heads = 2, .rpm = 7200, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, + { .name = "[ATA-4] Maxtor DiamondMax Plus 6800 (91024U3)", .internal_name = "91024U3", .model = "Maxtor 91024U3", .zones = 16, .avg_spt = 290, .heads = 3, .rpm = 7200, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, + { .name = "[ATA-4] Maxtor DiamondMax Plus 6800 (91366U4)", .internal_name = "91366U4", .model = "Maxtor 91366U4", .zones = 16, .avg_spt = 290, .heads = 4, .rpm = 7200, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, + { .name = "[ATA-4] Maxtor DiamondMax Plus 6800 (92049U6)", .internal_name = "92049U6", .model = "Maxtor 92049U6", .zones = 16, .avg_spt = 290, .heads = 6, .rpm = 7200, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, + { .name = "[ATA-4] Maxtor DiamondMax Plus 6800 (92732U8)", .internal_name = "92732U8", .model = "Maxtor 92732U8", .zones = 16, .avg_spt = 290, .heads = 8, .rpm = 7200, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, + { .name = "[ATA-4] Quantum Bigfoot TX4.3AT", .internal_name = "TX043A011", .model = "QUANTUM BIGFOOT TX4.3A", .zones = 2, .avg_spt = 220, .heads = 2, .rpm = 4000, .full_stroke_ms = 30, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 32 }, + { .name = "[ATA-4] Quantum Fireball ST3.2AT", .internal_name = "ST32A461", .model = "QUANTUM FIREBALL ST3.2A", .zones = 4, .avg_spt = 200, .heads = 4, .rpm = 5400, .full_stroke_ms = 21, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-4] Quantum Fireball SE4.3A", .internal_name = "SE43A011", .model = "QUANTUM FIREBALL SE4.3A", .zones = 2, .avg_spt = 200, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-4] Quantum Fireball SE6.4A", .internal_name = "SE64A011", .model = "QUANTUM FIREBALL SE6.4A", .zones = 3, .avg_spt = 200, .heads = 6, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-4] Quantum Fireball SE8.4A", .internal_name = "SE84A011", .model = "QUANTUM FIREBALL SE8.4A", .zones = 4, .avg_spt = 200, .heads = 8, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-4] Quantum Fireball EX12.7A", .internal_name = "EX12A012", .model = "QUANTUM FIREBALL EX12.7A", .version = "A0A.0D00", .zones = 4, .avg_spt = 200, .heads = 8, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-4] Quantum Fireball LCT-08 (LA04A011)", .internal_name = "LA04A011", .model = "QUANTUM FIREBALLlct08 04", .version = "A05.0X00", .zones = 8, .avg_spt = 280, .heads = 6, .rpm = 5400, .full_stroke_ms = 40, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-4] Seagate Medalist 2122", .internal_name = "ST32122A", .model = "ST32122A", .zones = 16, .avg_spt = 215, .heads = 2, .rpm = 4500, .full_stroke_ms = 23, .track_seek_ms = 3.8, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-4] Seagate Medalist 3321", .internal_name = "ST33221A", .model = "ST33221A", .zones = 16, .avg_spt = 210, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1.7, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-4] Seagate Medalist 4321", .internal_name = "ST34321A", .model = "ST34321A", .zones = 16, .avg_spt = 210, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2.2, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-4] Seagate Medalist 6531", .internal_name = "ST36531A", .model = "ST36531A", .zones = 16, .avg_spt = 215, .heads = 6, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1.7, .rcache_num_seg = 16, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-4] Seagate Medalist 8420", .internal_name = "ST38420A", .model = "ST38420A", .zones = 16, .avg_spt = 290, .heads = 4, .rpm = 5400, .full_stroke_ms = 16, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-4] Seagate Medalist 13030", .internal_name = "ST313030A", .model = "ST313030A", .zones = 16, .avg_spt = 290, .heads = 6, .rpm = 5400, .full_stroke_ms = 16, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-4] Seagate Medalist 17240", .internal_name = "ST317240A", .model = "ST317240A", .zones = 16, .avg_spt = 290, .heads = 8, .rpm = 5400, .full_stroke_ms = 16, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-4] Toshiba MK4006MAV", .internal_name = "MK4006MAV", .model = "TOSHIBA MK4006MAV", .zones = 8, .avg_spt = 230, .heads = 6, .rpm = 4200, .full_stroke_ms = 25, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-4] Western Digital Caviar 14300", .internal_name = "AC14300", .model = "WDC AC14300RT", .zones = 16, .avg_spt = 195, .heads = 2, .rpm = 5400, .full_stroke_ms = 21, .track_seek_ms = 5.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-4] Western Digital Caviar 23200", .internal_name = "AC23200", .model = "WDC AC23200LB", .zones = 16, .avg_spt = 210, .heads = 4, .rpm = 5400, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 256, .max_multiple = 32 }, + { .name = "[ATA-4] Western Digital Caviar 26400", .internal_name = "AC26400", .model = "WDC AC26400RN", .zones = 16, .avg_spt = 295, .heads = 5, .rpm = 5400, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-4] Western Digital Caviar 33200", .internal_name = "AC33200", .model = "WDC AC33200LA", .zones = 16, .avg_spt = 310, .heads = 5, .rpm = 5200, .full_stroke_ms = 40, .track_seek_ms = 3, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, + { .name = "[ATA-4] Western Digital Caviar 35100", .internal_name = "AC35100", .model = "WDC AC35100L", .version = "09.09M08", .zones = 16, .avg_spt = 315, .heads = 5, .rpm = 5400, .full_stroke_ms = 40, .track_seek_ms = 3, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, + { .name = "[ATA-5] IBM Travelstar 6GN", .internal_name = "DARA206000", .model = "IBM-DARA-206000", .zones = 12, .avg_spt = 292, .heads = 2, .rpm = 4200, .full_stroke_ms = 31, .track_seek_ms = 4, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] IBM Travelstar 9GN", .internal_name = "DARA209000", .model = "IBM-DARA-209000", .zones = 12, .avg_spt = 292, .heads = 3, .rpm = 4200, .full_stroke_ms = 31, .track_seek_ms = 4, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] IBM/Hitachi Travelstar 12GN", .internal_name = "DARA212000", .model = "IBM-DARA-212000", .zones = 12, .avg_spt = 292, .heads = 4, .rpm = 4200, .full_stroke_ms = 31, .track_seek_ms = 4, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, // Either Hitachi or IBM OEM + { .name = "[ATA-5] Maxtor DiamondMax VL 17", .internal_name = "90871U2", .model = "Maxtor 90871U2", .zones = 16, .avg_spt = 290, .heads = 3, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 0.9, .rcache_num_seg = 16, .rcache_seg_size = 256, .max_multiple = 32 }, + { .name = "[ATA-5] Maxtor DiamondMax VL 20 (91021U2)", .internal_name = "91021U2", .model = "Maxtor 91021U2", .zones = 16, .avg_spt = 295, .heads = 2, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Maxtor DiamondMax VL 20 (91531U3)", .internal_name = "91531U3", .model = "Maxtor 91531U3", .zones = 16, .avg_spt = 295, .heads = 3, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Maxtor DiamondMax VL 20 (92041U4)", .internal_name = "92041U4", .model = "Maxtor 92041U4", .zones = 16, .avg_spt = 295, .heads = 4, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 1, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Quantum Fireball EX3.2A", .internal_name = "EX32A012", .model = "QUANTUM FIREBALL EX3.2A", .zones = 1, .avg_spt = 210, .heads = 2, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball EX5.1A", .internal_name = "EX51A012", .model = "QUANTUM FIREBALL EX5.1A", .zones = 2, .avg_spt = 210, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball EX6.4A", .internal_name = "EX64A012", .model = "QUANTUM FIREBALL EX6.4A", .zones = 2, .avg_spt = 210, .heads = 4, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball EX10.2A", .internal_name = "EX10A011", .model = "QUANTUM FIREBALL EX10.2A", .zones = 3, .avg_spt = 210, .heads = 6, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball EX12.7A", .internal_name = "EX12A011", .model = "QUANTUM FIREBALL EX12.7A", .zones = 4, .avg_spt = 210, .heads = 8, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball CR4.3A", .internal_name = "CR43A013", .model = "QUANTUM FIREBALL CR4.3A", .zones = 2, .avg_spt = 310, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball CR6.4A", .internal_name = "CR64A011", .model = "QUANTUM FIREBALL CR6.4A", .zones = 2, .avg_spt = 310, .heads = 4, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball CR8.4A", .internal_name = "CR84A011", .model = "QUANTUM FIREBALL CR8.4A", .zones = 3, .avg_spt = 310, .heads = 6, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Quantum Fireball CR13.0A", .internal_name = "CR13A011", .model = "QUANTUM FIREBALL CR13.0A", .zones = 4, .avg_spt = 310, .heads = 8, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-5] Samsung SpinPoint V6800 (SV0682D)", .internal_name = "SV0682D", .model = "SAMSUNG SV0682D", .zones = 8, .avg_spt = 295, .heads = 2, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Samsung SpinPoint V6800 (SV1023D)", .internal_name = "SV1023D", .model = "SAMSUNG SV1023D", .zones = 8, .avg_spt = 295, .heads = 3, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Samsung SpinPoint V6800 (SV1364D)", .internal_name = "SV1364D", .model = "SAMSUNG SV1364D", .zones = 8, .avg_spt = 295, .heads = 4, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Samsung SpinPoint V6800 (SV1705D)", .internal_name = "SV1705D", .model = "SAMSUNG SV1705D", .zones = 8, .avg_spt = 295, .heads = 5, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Samsung SpinPoint V6800 (SV2046D)", .internal_name = "SV2046D", .model = "SAMSUNG SV2046D", .zones = 8, .avg_spt = 295, .heads = 6, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 1.3, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Seagate U8 - 4.3gb", .internal_name = "ST34313A", .model = "ST34313A", .zones = 16, .avg_spt = 289, .heads = 1, .rpm = 5400, .full_stroke_ms = 25, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Seagate U8 - 8.4gb", .internal_name = "ST38410A", .model = "ST38410A", .zones = 16, .avg_spt = 289, .heads = 2, .rpm = 5400, .full_stroke_ms = 25, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Seagate U8 - 13gb", .internal_name = "ST313021A", .model = "ST313021A", .zones = 16, .avg_spt = 289, .heads = 4, .rpm = 5400, .full_stroke_ms = 25, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Seagate U8 - 17.2gb", .internal_name = "ST317221A", .model = "ST317221A", .zones = 16, .avg_spt = 289, .heads = 3, .rpm = 5400, .full_stroke_ms = 25, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Western Digital Caviar 102AA", .internal_name = "WD102AA", .model = "WDC WD102AA-00ANA0", .zones = 16, .avg_spt = 295, .heads = 8, .rpm = 5400, .full_stroke_ms = 12, .track_seek_ms = 1.5, .rcache_num_seg = 16, .rcache_seg_size = 512, .max_multiple = 32 }, + { .name = "[ATA-5] Western Digital Expert", .internal_name = "WD135BA", .model = "WDC WD135BA-60AK", .zones = 16, .avg_spt = 350, .heads = 6, .rpm = 7200, .full_stroke_ms = 15, .track_seek_ms = 2, .rcache_num_seg = 16, .rcache_seg_size = 1920, .max_multiple = 32 }, // clang-format on }; @@ -586,6 +589,14 @@ hdd_preset_get_internal_name(int preset) return hdd_speed_presets[preset].internal_name; } +uint32_t +hdd_preset_get_rpm(int preset) +{ + if (preset < 0 || preset >= hdd_preset_get_num()) + return 0; + return hdd_speed_presets[preset].rpm; +} + int hdd_preset_get_from_internal_name(char *s) { @@ -625,8 +636,8 @@ hdd_preset_apply(int hdd_id) if (preset->model) hd->model = preset->model; - if (preset->version_ex) - hd->version_ex = preset->version_ex; + if (preset->version) + hd->version = preset->version; if (!hd->speed_preset) return; diff --git a/src/disk/hdd_audio.c b/src/disk/hdd_audio.c new file mode 100644 index 00000000000..902bd55b09b --- /dev/null +++ b/src/disk/hdd_audio.c @@ -0,0 +1,999 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Hard disk audio emulation. + * + * Authors: Toni Riikonen, + * + * Copyright 2026 Toni Riikonen. + */ + + #include +#include +#include +#include +#include <86box/86box.h> +#include <86box/hdd.h> +#include <86box/hdd_audio.h> +#include <86box/sound.h> +#include <86box/sound_util.h> +#include <86box/thread.h> +#include <86box/plat.h> +#include <86box/path.h> +#include <86box/ini.h> +#include <86box/mem.h> +#include <86box/rom.h> + +/* Maximum number of simultaneous seek sounds per HDD */ +#define HDD_MAX_SEEK_VOICES_PER_HDD 8 + +/* Maximum number of HDDs with audio emulation */ +#define HDD_AUDIO_MAX_DRIVES 8 + +typedef struct { + int active; + int position; + float volume; + int profile_id; /* Which profile's seek sound to use */ +} hdd_seek_voice_t; + +/* Per-HDD audio state */ +typedef struct { + int hdd_index; /* Index into hdd[] array */ + int profile_id; /* Audio profile ID */ + hdd_spindle_state_t spindle_state; + int spindle_pos; + int spindle_transition_pos; + hdd_seek_voice_t seek_voices[HDD_MAX_SEEK_VOICES_PER_HDD]; +} hdd_audio_drive_state_t; + +/* Audio samples structure for a profile */ +typedef struct { + int16_t *spindle_start_buffer; + int spindle_start_samples; + float spindle_start_volume; + int16_t *spindle_loop_buffer; + int spindle_loop_samples; + float spindle_loop_volume; + int16_t *spindle_stop_buffer; + int spindle_stop_samples; + float spindle_stop_volume; + int16_t *seek_buffer; + int seek_samples; + float seek_volume; + int loaded; +} hdd_audio_samples_t; + +/* Global audio profile configurations */ +static hdd_audio_profile_config_t audio_profiles[HDD_AUDIO_PROFILE_MAX]; +static int audio_profile_count = 0; + +/* Per-profile loaded samples */ +static hdd_audio_samples_t profile_samples[HDD_AUDIO_PROFILE_MAX]; + +/* Per-HDD audio states */ +static hdd_audio_drive_state_t drive_states[HDD_AUDIO_MAX_DRIVES]; +static int active_drive_count = 0; + +static mutex_t *hdd_audio_mutex = NULL; + +#ifdef ENABLE_HDD_AUDIO_LOG +int hdd_audio_do_log = ENABLE_HDD_AUDIO_LOG; + +static void +hdd_audio_log(const char *fmt, ...) +{ + va_list ap; + + if (hdd_audio_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define hdd_audio_log(fmt, ...) +#endif + +/* Load audio profiles from configuration file */ +void +hdd_audio_load_profiles(void) +{ + ini_t profiles_ini; + char cfg_fn[1024] = { 0 }; + + /* + * asset_getfile returns a path from the trusted asset search paths. + * The filename is hardcoded and validated against existing files. + */ + int ret = asset_getfile("assets/sounds/hdd/hdd_audio_profiles.cfg", cfg_fn, 1024); + if (!ret) { + hdd_audio_log("HDD Audio: Could not find hdd_audio_profiles.cfg\n"); + return; + } + + /* Validate that the path does not contain path traversal sequences */ + if (strstr(cfg_fn, "..") != NULL) { + hdd_audio_log("HDD Audio: Invalid path detected\n"); + return; + } + + /* Validate the path ends with our expected filename */ + const char *expected_suffix = "hdd_audio_profiles.cfg"; + size_t cfg_len = strlen(cfg_fn); + size_t suffix_len = strlen(expected_suffix); + if (cfg_len < suffix_len || strcmp(cfg_fn + cfg_len - suffix_len, expected_suffix) != 0) { + pclog("HDD Audio: Unexpected config path\n"); + return; + } + + profiles_ini = ini_read_ex(cfg_fn, 1); /* lgtm[cpp/path-injection] */ + if (profiles_ini == NULL) { + hdd_audio_log("HDD Audio: Failed to load hdd_audio_profiles.cfg\n"); + return; + } + + audio_profile_count = 0; + + /* Load profiles by trying known profile section names */ + for (int i = 0; i < HDD_AUDIO_PROFILE_MAX && audio_profile_count < HDD_AUDIO_PROFILE_MAX; i++) { + char section_name[64]; + sprintf(section_name, "Profile \"%d\"", i); + + ini_section_t cat = ini_find_section(profiles_ini, section_name); + if (cat == NULL) + continue; + + hdd_audio_profile_config_t *config = &audio_profiles[audio_profile_count]; + memset(config, 0, sizeof(hdd_audio_profile_config_t)); + + config->id = ini_section_get_int(cat, "id", i); + + const char *name = ini_section_get_string(cat, "name", "Unknown"); + strncpy(config->name, name, sizeof(config->name) - 1); + + const char *internal_name = ini_section_get_string(cat, "internal_name", "unknown"); + strncpy(config->internal_name, internal_name, sizeof(config->internal_name) - 1); + + config->rpm = ini_section_get_int(cat, "rpm", 0); + + /* Load spindle motor sample files */ + const char *file = ini_section_get_string(cat, "spindlemotor_start_file", ""); + strncpy(config->spindlemotor_start.filename, file, sizeof(config->spindlemotor_start.filename) - 1); + config->spindlemotor_start.volume = (float) ini_section_get_double(cat, "spindlemotor_start_volume", 1.0); + + file = ini_section_get_string(cat, "spindlemotor_loop_file", ""); + strncpy(config->spindlemotor_loop.filename, file, sizeof(config->spindlemotor_loop.filename) - 1); + config->spindlemotor_loop.volume = (float) ini_section_get_double(cat, "spindlemotor_loop_volume", 1.0); + + file = ini_section_get_string(cat, "spindlemotor_stop_file", ""); + strncpy(config->spindlemotor_stop.filename, file, sizeof(config->spindlemotor_stop.filename) - 1); + config->spindlemotor_stop.volume = (float) ini_section_get_double(cat, "spindlemotor_stop_volume", 1.0); + + /* Load seek sample file */ + file = ini_section_get_string(cat, "seek_track_file", ""); + strncpy(config->seek_track.filename, file, sizeof(config->seek_track.filename) - 1); + config->seek_track.volume = (float) ini_section_get_double(cat, "seek_track_volume", 1.0); + + hdd_audio_log("HDD Audio: Loaded profile %d: %s (%s)\n", + audio_profile_count, config->name, config->internal_name); + + audio_profile_count++; + } + + ini_close(profiles_ini); + + hdd_audio_log("HDD Audio: Loaded %d audio profiles\n", audio_profile_count); +} + +/* Public API functions */ +int +hdd_audio_get_profile_count(void) +{ + return audio_profile_count; +} + +const hdd_audio_profile_config_t * +hdd_audio_get_profile(int id) +{ + if (id < 0 || id >= audio_profile_count) + return NULL; + return &audio_profiles[id]; +} + +const char * +hdd_audio_get_profile_name(int id) +{ + if (id < 0 || id >= audio_profile_count) + return NULL; + return audio_profiles[id].name; +} + +const char * +hdd_audio_get_profile_internal_name(int id) +{ + if (id < 0 || id >= audio_profile_count) + return NULL; + return audio_profiles[id].internal_name; +} + +uint32_t +hdd_audio_get_profile_rpm(int id) +{ + if (id < 0 || id >= audio_profile_count) + return 0; + return audio_profiles[id].rpm; +} + +int +hdd_audio_get_profile_by_internal_name(const char *internal_name) +{ + if (!internal_name) + return 0; + + for (int i = 0; i < audio_profile_count; i++) { + if (strcmp(audio_profiles[i].internal_name, internal_name) == 0) + return i; + } + return 0; +} + +void +hdd_audio_close(void) +{ + /* Free all loaded profile samples */ + for (int i = 0; i < HDD_AUDIO_PROFILE_MAX; i++) { + if (profile_samples[i].spindle_start_buffer) { + free(profile_samples[i].spindle_start_buffer); + profile_samples[i].spindle_start_buffer = NULL; + } + if (profile_samples[i].spindle_loop_buffer) { + free(profile_samples[i].spindle_loop_buffer); + profile_samples[i].spindle_loop_buffer = NULL; + } + if (profile_samples[i].spindle_stop_buffer) { + free(profile_samples[i].spindle_stop_buffer); + profile_samples[i].spindle_stop_buffer = NULL; + } + if (profile_samples[i].seek_buffer) { + free(profile_samples[i].seek_buffer); + profile_samples[i].seek_buffer = NULL; + } + profile_samples[i].loaded = 0; + } + + if (hdd_audio_mutex) { + thread_close_mutex(hdd_audio_mutex); + hdd_audio_mutex = NULL; + } +} + +/* Load samples for a specific profile */ +static void +hdd_audio_load_profile_samples(int profile_id) +{ + if (profile_id < 0 || profile_id >= audio_profile_count) + return; + + hdd_audio_profile_config_t *config = &audio_profiles[profile_id]; + hdd_audio_samples_t *samples = &profile_samples[profile_id]; + + /* Already loaded? */ + if (samples->loaded) + return; + + /* Profile 0 is "None" - no audio */ + if (profile_id == 0 || strcmp(config->internal_name, "none") == 0) { + samples->loaded = 1; + return; + } + + hdd_audio_log("HDD Audio: Loading samples for profile %d (%s)\n", profile_id, config->name); + + /* Load spindle loop (main running sound) */ + if (config->spindlemotor_loop.filename[0]) { + samples->spindle_loop_buffer = sound_load_wav( + config->spindlemotor_loop.filename, + &samples->spindle_loop_samples); + if (samples->spindle_loop_buffer) { + samples->spindle_loop_volume = config->spindlemotor_loop.volume; + hdd_audio_log("HDD Audio: Loaded spindle loop, %d frames\n", samples->spindle_loop_samples); + } else { + hdd_audio_log("HDD Audio: Failed to load spindle loop: %s\n", config->spindlemotor_loop.filename); + } + } + + /* Load spindle start */ + if (config->spindlemotor_start.filename[0]) { + samples->spindle_start_buffer = sound_load_wav( + config->spindlemotor_start.filename, + &samples->spindle_start_samples); + if (samples->spindle_start_buffer) { + samples->spindle_start_volume = config->spindlemotor_start.volume; + hdd_audio_log("HDD Audio: Loaded spindle start, %d frames\n", samples->spindle_start_samples); + } + } + + /* Load spindle stop */ + if (config->spindlemotor_stop.filename[0]) { + samples->spindle_stop_buffer = sound_load_wav( + config->spindlemotor_stop.filename, + &samples->spindle_stop_samples); + if (samples->spindle_stop_buffer) { + samples->spindle_stop_volume = config->spindlemotor_stop.volume; + hdd_audio_log("HDD Audio: Loaded spindle stop, %d frames\n", samples->spindle_stop_samples); + } + } + + /* Load seek sound */ + if (config->seek_track.filename[0]) { + samples->seek_buffer = sound_load_wav( + config->seek_track.filename, + &samples->seek_samples); + if (samples->seek_buffer) { + samples->seek_volume = config->seek_track.volume; + hdd_audio_log("HDD Audio: Loaded seek sound, %d frames (%.1f ms)\n", + samples->seek_samples, (float)samples->seek_samples / 48.0f); + } else { + hdd_audio_log("HDD Audio: Failed to load seek sound: %s\n", config->seek_track.filename); + } + } + + samples->loaded = 1; +} + +/* Find drive state for a given HDD index, or NULL if not tracked */ +static hdd_audio_drive_state_t * +hdd_audio_find_drive_state(int hdd_index) +{ + for (int i = 0; i < active_drive_count; i++) { + if (drive_states[i].hdd_index == hdd_index) + return &drive_states[i]; + } + return NULL; +} + +void +hdd_audio_init(void) +{ + /* Initialize profile samples */ + memset(profile_samples, 0, sizeof(profile_samples)); + memset(drive_states, 0, sizeof(drive_states)); + active_drive_count = 0; + + hdd_audio_log("HDD Audio Init: audio_profile_count=%d\n", audio_profile_count); + + /* Create mutex BEFORE loading samples or calling spinup */ + if (!hdd_audio_mutex) + hdd_audio_mutex = thread_create_mutex(); + + /* Find all HDDs with valid audio profiles and initialize their states */ + for (int i = 0; i < HDD_NUM && active_drive_count < HDD_AUDIO_MAX_DRIVES; i++) { + if (hdd[i].bus_type != HDD_BUS_DISABLED && hdd[i].audio_profile > 0) { + hdd_audio_log("HDD Audio Init: HDD %d bus_type=%d audio_profile=%d\n", + i, hdd[i].bus_type, hdd[i].audio_profile); + + hdd_audio_drive_state_t *state = &drive_states[active_drive_count]; + state->hdd_index = i; + state->profile_id = hdd[i].audio_profile; + state->spindle_state = HDD_SPINDLE_STOPPED; + state->spindle_pos = 0; + state->spindle_transition_pos = 0; + + /* Initialize seek voices for this drive */ + for (int v = 0; v < HDD_MAX_SEEK_VOICES_PER_HDD; v++) { + state->seek_voices[v].active = 0; + state->seek_voices[v].position = 0; + state->seek_voices[v].volume = 1.0f; + state->seek_voices[v].profile_id = state->profile_id; + } + + /* Load samples for this profile if not already loaded */ + hdd_audio_load_profile_samples(state->profile_id); + + hdd_audio_log("HDD Audio: Initialized drive %d with profile %d (%s)\n", + i, state->profile_id, + hdd_audio_get_profile_name(state->profile_id)); + + active_drive_count++; + } + } + + hdd_audio_log("HDD Audio Init: %d active drives with audio\n", active_drive_count); + + /* Start spindle motors for all active drives */ + for (int i = 0; i < active_drive_count; i++) { + hdd_audio_spinup_drive(drive_states[i].hdd_index); + } + + sound_hdd_thread_init(); +} + +void +hdd_audio_reset(void) +{ + hdd_audio_log("HDD Audio: Reset\n"); + + /* Lock mutex to prevent audio callback from accessing buffers during reset */ + if (hdd_audio_mutex) + thread_wait_mutex(hdd_audio_mutex); + + /* Reset all drive states */ + for (int i = 0; i < active_drive_count; i++) { + drive_states[i].spindle_state = HDD_SPINDLE_STOPPED; + drive_states[i].spindle_pos = 0; + drive_states[i].spindle_transition_pos = 0; + for (int v = 0; v < HDD_MAX_SEEK_VOICES_PER_HDD; v++) { + drive_states[i].seek_voices[v].active = 0; + drive_states[i].seek_voices[v].position = 0; + drive_states[i].seek_voices[v].volume = 1.0f; + } + } + active_drive_count = 0; + + /* Free previously loaded samples (but keep profiles) */ + for (int i = 0; i < HDD_AUDIO_PROFILE_MAX; i++) { + if (profile_samples[i].spindle_start_buffer) { + free(profile_samples[i].spindle_start_buffer); + profile_samples[i].spindle_start_buffer = NULL; + } + if (profile_samples[i].spindle_loop_buffer) { + free(profile_samples[i].spindle_loop_buffer); + profile_samples[i].spindle_loop_buffer = NULL; + } + if (profile_samples[i].spindle_stop_buffer) { + free(profile_samples[i].spindle_stop_buffer); + profile_samples[i].spindle_stop_buffer = NULL; + } + if (profile_samples[i].seek_buffer) { + free(profile_samples[i].seek_buffer); + profile_samples[i].seek_buffer = NULL; + } + profile_samples[i].loaded = 0; + } + + if (hdd_audio_mutex) + thread_release_mutex(hdd_audio_mutex); + + /* Find all HDDs with valid audio profiles and initialize their states */ + for (int i = 0; i < HDD_NUM && active_drive_count < HDD_AUDIO_MAX_DRIVES; i++) { + if (hdd[i].bus_type != HDD_BUS_DISABLED && hdd[i].audio_profile > 0) { + hdd_audio_log("HDD Audio Reset: HDD %d audio_profile=%d\n", i, hdd[i].audio_profile); + + hdd_audio_drive_state_t *state = &drive_states[active_drive_count]; + state->hdd_index = i; + state->profile_id = hdd[i].audio_profile; + state->spindle_state = HDD_SPINDLE_STOPPED; + state->spindle_pos = 0; + state->spindle_transition_pos = 0; + + /* Initialize seek voices for this drive */ + for (int v = 0; v < HDD_MAX_SEEK_VOICES_PER_HDD; v++) { + state->seek_voices[v].active = 0; + state->seek_voices[v].position = 0; + state->seek_voices[v].volume = 1.0f; + state->seek_voices[v].profile_id = state->profile_id; + } + + /* Load samples for this profile if not already loaded */ + hdd_audio_load_profile_samples(state->profile_id); + + hdd_audio_log("HDD Audio: Reset drive %d with profile %d (%s)\n", + i, state->profile_id, + hdd_audio_get_profile_name(state->profile_id)); + + active_drive_count++; + } + } + + hdd_audio_log("HDD Audio Reset: %d active drives with audio\n", active_drive_count); + + /* Start spindle motors for all active drives */ + for (int i = 0; i < active_drive_count; i++) { + hdd_audio_spinup_drive(drive_states[i].hdd_index); + } +} + +void +hdd_audio_seek(hard_disk_t *hdd_drive, uint32_t new_cylinder) +{ + uint32_t cylinder_diff = abs((int) hdd_drive->cur_cylinder - (int) new_cylinder); + + if (cylinder_diff == 0) + return; + + /* Find the drive state for this HDD */ + hdd_audio_drive_state_t *drive_state = NULL; + for (int i = 0; i < active_drive_count; i++) { + if (&hdd[drive_states[i].hdd_index] == hdd_drive) { + drive_state = &drive_states[i]; + break; + } + } + + /* If no drive state found, drive has no audio profile */ + if (!drive_state) + return; + + int profile_id = drive_state->profile_id; + + /* No audio profile selected */ + if (profile_id == 0 || profile_id >= audio_profile_count) + return; + + /* Load samples if not already loaded */ + if (!profile_samples[profile_id].loaded) + hdd_audio_load_profile_samples(profile_id); + + hdd_audio_samples_t *samples = &profile_samples[profile_id]; + + if (!samples->seek_buffer || samples->seek_samples == 0) { + return; + } + + /* Mutex must exist */ + if (!hdd_audio_mutex) + return; + + int min_seek_spacing = 0; + if (hdd_drive->cyl_switch_usec > 0) + min_seek_spacing = (int)(hdd_drive->cyl_switch_usec * 48000.0 / 1000000.0); + + thread_wait_mutex(hdd_audio_mutex); + + /* Check if we should skip due to minimum spacing (per-drive) */ + for (int v = 0; v < HDD_MAX_SEEK_VOICES_PER_HDD; v++) { + if (drive_state->seek_voices[v].active) { + int pos = drive_state->seek_voices[v].position; + if (pos >= 0 && pos < min_seek_spacing) { + thread_release_mutex(hdd_audio_mutex); + return; + } + } + } + + /* Find a free seek voice for this drive */ + for (int v = 0; v < HDD_MAX_SEEK_VOICES_PER_HDD; v++) { + if (!drive_state->seek_voices[v].active) { + drive_state->seek_voices[v].active = 1; + drive_state->seek_voices[v].position = 0; + drive_state->seek_voices[v].volume = samples->seek_volume; + drive_state->seek_voices[v].profile_id = profile_id; + thread_release_mutex(hdd_audio_mutex); + return; + } + } + + thread_release_mutex(hdd_audio_mutex); +} + +/* Spinup a specific drive by HDD index */ +void +hdd_audio_spinup_drive(int hdd_index) +{ + hdd_audio_drive_state_t *state = hdd_audio_find_drive_state(hdd_index); + if (!state) + return; + + if (state->spindle_state == HDD_SPINDLE_RUNNING || state->spindle_state == HDD_SPINDLE_STARTING) + return; + + hdd_audio_log("HDD Audio: Spinup requested for drive %d (current state: %d)\n", hdd_index, state->spindle_state); + + if (hdd_audio_mutex) + thread_wait_mutex(hdd_audio_mutex); + state->spindle_state = HDD_SPINDLE_STARTING; + state->spindle_transition_pos = 0; + if (hdd_audio_mutex) + thread_release_mutex(hdd_audio_mutex); +} + +/* Spindown a specific drive by HDD index */ +void +hdd_audio_spindown_drive(int hdd_index) +{ + hdd_audio_drive_state_t *state = hdd_audio_find_drive_state(hdd_index); + if (!state) + return; + + if (state->spindle_state == HDD_SPINDLE_STOPPED || state->spindle_state == HDD_SPINDLE_STOPPING) + return; + + hdd_audio_log("HDD Audio: Spindown requested for drive %d (current state: %d)\n", hdd_index, state->spindle_state); + + if (hdd_audio_mutex) + thread_wait_mutex(hdd_audio_mutex); + state->spindle_state = HDD_SPINDLE_STOPPING; + state->spindle_transition_pos = 0; + if (hdd_audio_mutex) + thread_release_mutex(hdd_audio_mutex); +} + +/* Legacy functions for backward compatibility - operate on all drives */ +void +hdd_audio_spinup(void) +{ + for (int i = 0; i < active_drive_count; i++) { + hdd_audio_spinup_drive(drive_states[i].hdd_index); + } +} + +void +hdd_audio_spindown(void) +{ + for (int i = 0; i < active_drive_count; i++) { + hdd_audio_spindown_drive(drive_states[i].hdd_index); + } +} + +hdd_spindle_state_t +hdd_audio_get_spindle_state(void) +{ + /* Return running if any drive is running */ + for (int i = 0; i < active_drive_count; i++) { + if (drive_states[i].spindle_state == HDD_SPINDLE_RUNNING) + return HDD_SPINDLE_RUNNING; + } + for (int i = 0; i < active_drive_count; i++) { + if (drive_states[i].spindle_state == HDD_SPINDLE_STARTING) + return HDD_SPINDLE_STARTING; + } + for (int i = 0; i < active_drive_count; i++) { + if (drive_states[i].spindle_state == HDD_SPINDLE_STOPPING) + return HDD_SPINDLE_STOPPING; + } + return HDD_SPINDLE_STOPPED; +} + +hdd_spindle_state_t +hdd_audio_get_drive_spindle_state(int hdd_index) +{ + hdd_audio_drive_state_t *state = hdd_audio_find_drive_state(hdd_index); + if (!state) + return HDD_SPINDLE_STOPPED; + return state->spindle_state; +} + +/* Helper: Mix spindle start sound into float buffer */ +static void +hdd_audio_mix_spindle_start_float(hdd_audio_drive_state_t *state, hdd_audio_samples_t *samples, + float *float_buffer, int frames_in_buffer) +{ + if (!samples->spindle_start_buffer || samples->spindle_start_samples <= 0) { + state->spindle_state = HDD_SPINDLE_RUNNING; + state->spindle_pos = 0; + return; + } + + float start_volume = samples->spindle_start_volume; + for (int i = 0; i < frames_in_buffer && state->spindle_transition_pos < samples->spindle_start_samples; i++) { + float left_sample = (float) samples->spindle_start_buffer[state->spindle_transition_pos * 2] / 131072.0f * start_volume; + float right_sample = (float) samples->spindle_start_buffer[state->spindle_transition_pos * 2 + 1] / 131072.0f * start_volume; + float_buffer[i * 2] += left_sample; + float_buffer[i * 2 + 1] += right_sample; + state->spindle_transition_pos++; + } + + if (state->spindle_transition_pos >= samples->spindle_start_samples) { + state->spindle_state = HDD_SPINDLE_RUNNING; + state->spindle_pos = 0; + hdd_audio_log("HDD Audio: Drive %d spinup complete, now running\n", state->hdd_index); + } +} + +/* Helper: Mix spindle loop sound into float buffer */ +static void +hdd_audio_mix_spindle_loop_float(hdd_audio_drive_state_t *state, hdd_audio_samples_t *samples, + float *float_buffer, int frames_in_buffer) +{ + if (!samples->spindle_loop_buffer || samples->spindle_loop_samples <= 0) + return; + + float spindle_volume = samples->spindle_loop_volume; + for (int i = 0; i < frames_in_buffer; i++) { + float left_sample = (float) samples->spindle_loop_buffer[state->spindle_pos * 2] / 131072.0f * spindle_volume; + float right_sample = (float) samples->spindle_loop_buffer[state->spindle_pos * 2 + 1] / 131072.0f * spindle_volume; + float_buffer[i * 2] += left_sample; + float_buffer[i * 2 + 1] += right_sample; + + state->spindle_pos++; + if (state->spindle_pos >= samples->spindle_loop_samples) { + state->spindle_pos = 0; + } + } +} + +/* Helper: Mix spindle stop sound into float buffer */ +static void +hdd_audio_mix_spindle_stop_float(hdd_audio_drive_state_t *state, hdd_audio_samples_t *samples, + float *float_buffer, int frames_in_buffer) +{ + if (!samples->spindle_stop_buffer || samples->spindle_stop_samples <= 0) { + state->spindle_state = HDD_SPINDLE_STOPPED; + return; + } + + float stop_volume = samples->spindle_stop_volume; + for (int i = 0; i < frames_in_buffer && state->spindle_transition_pos < samples->spindle_stop_samples; i++) { + float left_sample = (float) samples->spindle_stop_buffer[state->spindle_transition_pos * 2] / 131072.0f * stop_volume; + float right_sample = (float) samples->spindle_stop_buffer[state->spindle_transition_pos * 2 + 1] / 131072.0f * stop_volume; + float_buffer[i * 2] += left_sample; + float_buffer[i * 2 + 1] += right_sample; + state->spindle_transition_pos++; + } + + if (state->spindle_transition_pos >= samples->spindle_stop_samples) { + state->spindle_state = HDD_SPINDLE_STOPPED; + hdd_audio_log("HDD Audio: Drive %d spindown complete, now stopped\n", state->hdd_index); + } +} + +/* Helper: Mix seek sounds into float buffer */ +static void +hdd_audio_mix_seek_float(hdd_audio_drive_state_t *state, float *float_buffer, int frames_in_buffer) +{ + for (int v = 0; v < HDD_MAX_SEEK_VOICES_PER_HDD; v++) { + if (!state->seek_voices[v].active) + continue; + + int seek_profile_id = state->seek_voices[v].profile_id; + hdd_audio_samples_t *seek_samples = &profile_samples[seek_profile_id]; + if (!seek_samples->seek_buffer || seek_samples->seek_samples == 0) + continue; + + float voice_vol = state->seek_voices[v].volume; + int pos = state->seek_voices[v].position; + if (pos < 0) pos = 0; + + for (int i = 0; i < frames_in_buffer && pos < seek_samples->seek_samples; i++, pos++) { + float seek_left = (float) seek_samples->seek_buffer[pos * 2] / 131072.0f * voice_vol; + float seek_right = (float) seek_samples->seek_buffer[pos * 2 + 1] / 131072.0f * voice_vol; + + float_buffer[i * 2] += seek_left; + float_buffer[i * 2 + 1] += seek_right; + } + + if (pos >= seek_samples->seek_samples) { + state->seek_voices[v].active = 0; + state->seek_voices[v].position = 0; + } else { + state->seek_voices[v].position = pos; + } + } +} + +/* Helper: Mix spindle start sound into int16 buffer */ +static void +hdd_audio_mix_spindle_start_int16(hdd_audio_drive_state_t *state, hdd_audio_samples_t *samples, + int16_t *buffer, int frames_in_buffer) +{ + if (!samples->spindle_start_buffer || samples->spindle_start_samples <= 0) { + state->spindle_state = HDD_SPINDLE_RUNNING; + state->spindle_pos = 0; + return; + } + + float start_volume = samples->spindle_start_volume; + for (int i = 0; i < frames_in_buffer && state->spindle_transition_pos < samples->spindle_start_samples; i++) { + int32_t left = buffer[i * 2] + (int32_t)(samples->spindle_start_buffer[state->spindle_transition_pos * 2] * start_volume); + int32_t right = buffer[i * 2 + 1] + (int32_t)(samples->spindle_start_buffer[state->spindle_transition_pos * 2 + 1] * start_volume); + if (left > 32767) left = 32767; + if (left < -32768) left = -32768; + if (right > 32767) right = 32767; + if (right < -32768) right = -32768; + buffer[i * 2] = (int16_t) left; + buffer[i * 2 + 1] = (int16_t) right; + state->spindle_transition_pos++; + } + + if (state->spindle_transition_pos >= samples->spindle_start_samples) { + state->spindle_state = HDD_SPINDLE_RUNNING; + state->spindle_pos = 0; + hdd_audio_log("HDD Audio: Drive %d spinup complete, now running\n", state->hdd_index); + } +} + +/* Helper: Mix spindle loop sound into int16 buffer */ +static void +hdd_audio_mix_spindle_loop_int16(hdd_audio_drive_state_t *state, hdd_audio_samples_t *samples, + int16_t *buffer, int frames_in_buffer) +{ + if (!samples->spindle_loop_buffer || samples->spindle_loop_samples <= 0) + return; + + float spindle_volume = samples->spindle_loop_volume; + for (int i = 0; i < frames_in_buffer; i++) { + int32_t left = buffer[i * 2] + (int32_t)(samples->spindle_loop_buffer[state->spindle_pos * 2] * spindle_volume); + int32_t right = buffer[i * 2 + 1] + (int32_t)(samples->spindle_loop_buffer[state->spindle_pos * 2 + 1] * spindle_volume); + if (left > 32767) left = 32767; + if (left < -32768) left = -32768; + if (right > 32767) right = 32767; + if (right < -32768) right = -32768; + buffer[i * 2] = (int16_t) left; + buffer[i * 2 + 1] = (int16_t) right; + + state->spindle_pos++; + if (state->spindle_pos >= samples->spindle_loop_samples) { + state->spindle_pos = 0; + } + } +} + +/* Helper: Mix spindle stop sound into int16 buffer */ +static void +hdd_audio_mix_spindle_stop_int16(hdd_audio_drive_state_t *state, hdd_audio_samples_t *samples, + int16_t *buffer, int frames_in_buffer) +{ + if (!samples->spindle_stop_buffer || samples->spindle_stop_samples <= 0) { + state->spindle_state = HDD_SPINDLE_STOPPED; + return; + } + + float stop_volume = samples->spindle_stop_volume; + for (int i = 0; i < frames_in_buffer && state->spindle_transition_pos < samples->spindle_stop_samples; i++) { + int32_t left = buffer[i * 2] + (int32_t)(samples->spindle_stop_buffer[state->spindle_transition_pos * 2] * stop_volume); + int32_t right = buffer[i * 2 + 1] + (int32_t)(samples->spindle_stop_buffer[state->spindle_transition_pos * 2 + 1] * stop_volume); + if (left > 32767) left = 32767; + if (left < -32768) left = -32768; + if (right > 32767) right = 32767; + if (right < -32768) right = -32768; + buffer[i * 2] = (int16_t) left; + buffer[i * 2 + 1] = (int16_t) right; + state->spindle_transition_pos++; + } + + if (state->spindle_transition_pos >= samples->spindle_stop_samples) { + state->spindle_state = HDD_SPINDLE_STOPPED; + hdd_audio_log("HDD Audio: Drive %d spindown complete, now stopped\n", state->hdd_index); + } +} + +/* Helper: Mix seek sounds into int16 buffer */ +static void +hdd_audio_mix_seek_int16(hdd_audio_drive_state_t *state, int16_t *buffer, int frames_in_buffer) +{ + for (int v = 0; v < HDD_MAX_SEEK_VOICES_PER_HDD; v++) { + if (!state->seek_voices[v].active) + continue; + + int seek_profile_id = state->seek_voices[v].profile_id; + hdd_audio_samples_t *seek_samples = &profile_samples[seek_profile_id]; + if (!seek_samples->seek_buffer || seek_samples->seek_samples == 0) + continue; + + float voice_vol = state->seek_voices[v].volume; + int pos = state->seek_voices[v].position; + if (pos < 0) pos = 0; + + for (int i = 0; i < frames_in_buffer && pos < seek_samples->seek_samples; i++, pos++) { + int32_t left = buffer[i * 2] + (int32_t)(seek_samples->seek_buffer[pos * 2] * voice_vol); + int32_t right = buffer[i * 2 + 1] + (int32_t)(seek_samples->seek_buffer[pos * 2 + 1] * voice_vol); + + if (left > 32767) left = 32767; + if (left < -32768) left = -32768; + if (right > 32767) right = 32767; + if (right < -32768) right = -32768; + + buffer[i * 2] = (int16_t) left; + buffer[i * 2 + 1] = (int16_t) right; + } + + if (pos >= seek_samples->seek_samples) { + state->seek_voices[v].active = 0; + state->seek_voices[v].position = 0; + } else { + state->seek_voices[v].position = pos; + } + } +} + +/* Process a single drive's audio in float mode */ +static void +hdd_audio_process_drive_float(hdd_audio_drive_state_t *state, float *float_buffer, int frames_in_buffer) +{ + int profile_id = state->profile_id; + + if (profile_id <= 0 || profile_id >= HDD_AUDIO_PROFILE_MAX) + return; + + hdd_audio_samples_t *samples = &profile_samples[profile_id]; + if (!samples->loaded) + return; + + /* Handle spindle states for this drive */ + switch (state->spindle_state) { + case HDD_SPINDLE_STARTING: + hdd_audio_mix_spindle_start_float(state, samples, float_buffer, frames_in_buffer); + break; + case HDD_SPINDLE_RUNNING: + hdd_audio_mix_spindle_loop_float(state, samples, float_buffer, frames_in_buffer); + break; + case HDD_SPINDLE_STOPPING: + hdd_audio_mix_spindle_stop_float(state, samples, float_buffer, frames_in_buffer); + break; + case HDD_SPINDLE_STOPPED: + default: + break; + } + + /* Seek sounds - only play when spindle is running */ + if (samples->seek_buffer && samples->seek_samples > 0 && + hdd_audio_mutex && state->spindle_state == HDD_SPINDLE_RUNNING) { + thread_wait_mutex(hdd_audio_mutex); + hdd_audio_mix_seek_float(state, float_buffer, frames_in_buffer); + thread_release_mutex(hdd_audio_mutex); + } +} + +/* Process a single drive's audio in int16 mode */ +static void +hdd_audio_process_drive_int16(hdd_audio_drive_state_t *state, int16_t *buffer, int frames_in_buffer) +{ + int profile_id = state->profile_id; + + if (profile_id <= 0 || profile_id >= HDD_AUDIO_PROFILE_MAX) + return; + + hdd_audio_samples_t *samples = &profile_samples[profile_id]; + if (!samples->loaded) + return; + + /* Handle spindle states for this drive */ + switch (state->spindle_state) { + case HDD_SPINDLE_STARTING: + hdd_audio_mix_spindle_start_int16(state, samples, buffer, frames_in_buffer); + break; + case HDD_SPINDLE_RUNNING: + hdd_audio_mix_spindle_loop_int16(state, samples, buffer, frames_in_buffer); + break; + case HDD_SPINDLE_STOPPING: + hdd_audio_mix_spindle_stop_int16(state, samples, buffer, frames_in_buffer); + break; + case HDD_SPINDLE_STOPPED: + default: + break; + } + + /* Seek sounds - only play when spindle is running */ + if (samples->seek_buffer && samples->seek_samples > 0 && + hdd_audio_mutex && state->spindle_state == HDD_SPINDLE_RUNNING) { + thread_wait_mutex(hdd_audio_mutex); + hdd_audio_mix_seek_int16(state, buffer, frames_in_buffer); + thread_release_mutex(hdd_audio_mutex); + } +} + +void +hdd_audio_callback(int16_t *buffer, int length) +{ + int frames_in_buffer = length / 2; + + if (sound_is_float) { + float *float_buffer = (float *) buffer; + + /* Initialize buffer to silence */ + for (int i = 0; i < length; i++) { + float_buffer[i] = 0.0f; + } + + /* Process each active drive */ + for (int d = 0; d < active_drive_count; d++) { + hdd_audio_process_drive_float(&drive_states[d], float_buffer, frames_in_buffer); + } + } else { + /* Initialize buffer to silence */ + for (int i = 0; i < length; i++) { + buffer[i] = 0; + } + + /* Process each active drive */ + for (int d = 0; d < active_drive_count; d++) { + hdd_audio_process_drive_int16(&drive_states[d], buffer, frames_in_buffer); + } + } +} \ No newline at end of file diff --git a/src/disk/mo.c b/src/disk/mo.c index 5ffe74f78da..079e82c6ee4 100644 --- a/src/disk/mo.c +++ b/src/disk/mo.c @@ -254,7 +254,7 @@ mo_disk_close(const mo_t *dev) mo_disk_unload(dev); memcpy(dev->drv->prev_image_path, dev->drv->image_path, - sizeof(dev->drv->prev_image_path)); + sizeof(dev->drv->image_path)); memset(dev->drv->image_path, 0, sizeof(dev->drv->image_path)); dev->drv->medium_size = 0; diff --git a/src/disk/rdisk.c b/src/disk/rdisk.c index 683b1e9632b..87e9eb5e41e 100644 --- a/src/disk/rdisk.c +++ b/src/disk/rdisk.c @@ -307,7 +307,7 @@ rdisk_disk_close(const rdisk_t *dev) rdisk_disk_unload(dev); memcpy(dev->drv->prev_image_path, dev->drv->image_path, - sizeof(dev->drv->prev_image_path)); + sizeof(dev->drv->image_path)); memset(dev->drv->image_path, 0, sizeof(dev->drv->image_path)); dev->drv->medium_size = 0; diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index c1bf0461895..d6d27da3bb8 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -77,7 +77,7 @@ int lastbyte = 0; int floppymodified[4]; int floppyrate[4]; -int fdc_current[FDC_MAX] = { 0, 0 }; +int fdc_current[FDC_MAX] = { FDC_INTERNAL, 0 }; volatile int fdcinited = 0; @@ -784,6 +784,9 @@ fdc_sis(fdc_t *fdc) static void fdc_soft_reset(fdc_t *fdc) { + /* Reset boot status to POST on controller soft reset */ + fdd_boot_status_reset(); + if (fdc->power_down) { timer_set_delay_u64(&fdc->timer, 1000 * TIMER_USEC); fdc->interrupt = -5; @@ -1139,7 +1142,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) timer_set_delay_u64(&fdc->timer, 1000 * TIMER_USEC); else timer_set_delay_u64(&fdc->timer, 256 * TIMER_USEC); - break; + break; default: timer_set_delay_u64(&fdc->timer, 256 * TIMER_USEC); break; @@ -1879,13 +1882,17 @@ fdc_callback(void *priv) fdc->st0 = 0x20 | (fdc->params[0] & 3); if (!fdd_track0(drive_num)) fdc->st0 |= 0x50; - if (fdc->flags & FDC_FLAG_PCJR) { - fdc->fintr = 1; - fdc->interrupt = -4; - } else - fdc->interrupt = -3; - timer_set_delay_u64(&fdc->timer, 2048 * TIMER_USEC); fdc->stat = 0x10 | (1 << fdc->rw_drive); + if (fdd_get_turbo(drive_num)) { + if (fdc->flags & FDC_FLAG_PCJR) { + fdc->fintr = 1; + fdc->interrupt = -4; + } else { + fdc->interrupt = -3; + } + timer_set_delay_u64(&fdc->timer, 2048 * TIMER_USEC); + } + /* Interrupts and callbacks in the fdd callback function (fdc_seek_complete_interrupt) */ return; case 0x0d: /*Format track*/ if (fdc->format_state == 1) { @@ -2403,6 +2410,9 @@ fdc_reset(void *priv) fdc_t *fdc = (fdc_t *) priv; + /* Reset boot status to POST on controller reset */ + fdd_boot_status_reset(); + default_rwc = (fdc->flags & FDC_FLAG_START_RWC_1) ? 1 : 0; fdc->enable_3f1 = 1; @@ -2872,4 +2882,4 @@ const device_t fdc_ps2_mca_device = { .speed_changed = NULL, .force_redraw = NULL, .config = NULL -}; \ No newline at end of file +}; diff --git a/src/floppy/fdd.c b/src/floppy/fdd.c index 164c0b03701..89ec2e9f6e8 100644 --- a/src/floppy/fdd.c +++ b/src/floppy/fdd.c @@ -101,7 +101,10 @@ typedef struct fdd_pending_op_t { static fdd_pending_op_t fdd_pending[FDD_NUM]; -char floppyfns[FDD_NUM][512]; +/* BIOS boot status tracking */ +static bios_boot_status_t bios_boot_status = BIOS_BOOT_POST; + +char floppyfns[FDD_NUM][MAX_IMAGE_PATH_LEN]; char *fdd_image_history[FDD_NUM][FLOPPY_IMAGE_HISTORY]; pc_timer_t fdd_poll_time[FDD_NUM]; @@ -212,9 +215,9 @@ int fdd_do_log = ENABLE_FDD_LOG; static void fdd_log(const char *fmt, ...) { - va_list ap, ap_copy; + va_list ap; char timebuf[32]; - char fullbuf[1056]; // 32 + 1024 bytes for timestamp + message + char fullbuf[1056]; /* 32 + 1024 bytes for timestamp + message */ if (fdd_do_log) { uint32_t ticks = plat_get_ticks(); @@ -224,27 +227,58 @@ fdd_log(const char *fmt, ...) snprintf(timebuf, sizeof(timebuf), "[%07u.%03u] ", seconds, milliseconds); va_start(ap, fmt); - va_copy(ap_copy, ap); - strcpy(fullbuf, timebuf); - vsnprintf(fullbuf + strlen(timebuf), sizeof(fullbuf) - strlen(timebuf), fmt, ap_copy); - - va_end(ap_copy); - va_end(ap); - - va_start(ap, fmt); + vsnprintf(fullbuf + strlen(timebuf), sizeof(fullbuf) - strlen(timebuf), fmt, ap); va_end(ap); - char *msg = fullbuf; - va_start(ap, fmt); - pclog_ex("%s", (va_list) &msg); - va_end(ap); + pclog("%s", fullbuf); } } #else # define fdd_log(fmt, ...) #endif +/* + * BIOS boot status functions + * + * These functions track whether the system is in BIOS POST (Power-On Self Test) + * or has transitioned to normal operation. The POST state is set on: + * - System hard reset (fdd_reset) + * - FDC soft reset (fdd_boot_status_reset) + * + * POST is considered complete when the first floppy read operation occurs, + * indicating that BIOS has finished POST and is attempting to boot. + */ +bios_boot_status_t +fdd_get_boot_status(void) +{ + return bios_boot_status; +} + +void +fdd_set_boot_status(bios_boot_status_t status) +{ + if (bios_boot_status != status) { + fdd_log("BIOS boot status changed: %s -> %s\n", + bios_boot_status == BIOS_BOOT_POST ? "POST" : "NORMAL", + status == BIOS_BOOT_POST ? "POST" : "NORMAL"); + bios_boot_status = status; + } +} + +void +fdd_boot_status_reset(void) +{ + fdd_log("BIOS boot status reset to POST\n"); + bios_boot_status = BIOS_BOOT_POST; +} + +int +fdd_is_post_complete(void) +{ + return (bios_boot_status == BIOS_BOOT_NORMAL); +} + void fdd_set_audio_profile(int drive, int profile) { @@ -365,7 +399,7 @@ void fdd_seek(int drive, int track_diff) { fdd_log("fdd_seek(drive=%d, track_diff=%d)\n", drive, track_diff); - if (!track_diff) + if (track_diff == 0) return; if (fdd_seek_in_progress[drive]) { @@ -385,9 +419,9 @@ fdd_seek(int drive, int track_diff) fdd_changed[drive] = 0; - if (fdd[drive].turbo) + if (fdd[drive].turbo) { fdd_do_seek(drive, fdd[drive].track); - else { + } else { /* Trigger appropriate audio for track movements */ int actual_track_diff = abs(old_track - fdd[drive].track); if (actual_track_diff > 0) { @@ -395,11 +429,6 @@ fdd_seek(int drive, int track_diff) fdd_audio_play_multi_track_seek(drive, old_track, fdd[drive].track); } - if (old_track + track_diff < 0) { - fdd_do_seek(drive, fdd[drive].track); - return; - } - fdd_seek_in_progress[drive] = 1; if (!fdd_seek_timer[drive].callback) { @@ -411,6 +440,10 @@ fdd_seek(int drive, int track_diff) /* Get seek timings from audio profile configuration with direction awareness */ double seek_time_us = fdd_audio_get_seek_time(drive, actual_track_diff, is_seek_down); + if (seek_time_us < 1) { + seek_time_us = DEFAULT_SEEK_TIME_MS * 1000; + } + fdd_log("Seek timing for drive %d: %.2f µs (%s)\n", drive, seek_time_us, is_seek_down ? "DOWN" : "UP"); uint64_t seek_delay_us = seek_time_us * TIMER_USEC; @@ -451,7 +484,7 @@ fdd_type_invert_densel(int type) int ret; if (drive_types[type].flags & FLAG_PS2) - ret = (!!strstr(machine_getname(), "PS/1")) || (!!strstr(machine_getname(), "PS/2")) || (!!strstr(machine_getname(), "PS/55")); + ret = (!!strstr(machine_getname(machine), "PS/1")) || (!!strstr(machine_getname(machine), "PS/2")) || (!!strstr(machine_getname(machine), "PS/55")); else ret = drive_types[type].flags & FLAG_INVERT_DENSEL; @@ -686,6 +719,7 @@ fdd_close(int drive) drives[drive].format = NULL; drives[drive].byteperiod = NULL; drives[drive].stop = NULL; + fdd_seek_in_progress[drive] = 0; d86f_destroy(drive); ui_sb_update_icon_state(SB_FLOPPY | drive, 1); } @@ -774,9 +808,15 @@ fdd_get_bitcell_period(int rate) void fdd_reset(void) { + /* Reset boot status to POST on system reset */ + fdd_boot_status_reset(); + for (uint8_t i = 0; i < FDD_NUM; i++) { drives[i].id = i; timer_add(&(fdd_poll_time[i]), fdd_poll, &drives[i], 0); + + /* Clear any pending seek state */ + fdd_seek_in_progress[i] = 0; } } @@ -785,6 +825,11 @@ fdd_readsector(int drive, int sector, int track, int side, int density, int sect { fdd_log("fdd_readsector(%d, %d, %d, %d, %d, %d)\n", drive, sector, track, side, density, sector_size); + /* First floppy read operation marks POST as complete */ + if (bios_boot_status == BIOS_BOOT_POST) { + fdd_set_boot_status(BIOS_BOOT_NORMAL); + } + if (fdd_seek_in_progress[drive]) { fdd_log("Seek in progress on drive %d, deferring READ (trk=%d->%d, side=%d, sec=%d)\n", drive, fdd[drive].track, track, side, sector); diff --git a/src/floppy/fdd_audio.c b/src/floppy/fdd_audio.c index 5fe5e6358a3..62e1881efe0 100644 --- a/src/floppy/fdd_audio.c +++ b/src/floppy/fdd_audio.c @@ -31,6 +31,7 @@ #include <86box/plat.h> #include <86box/path.h> #include <86box/ini.h> +#include <86box/sound_util.h> #ifndef DISABLE_FDD_AUDIO @@ -38,39 +39,6 @@ static fdd_audio_profile_config_t audio_profiles[FDD_AUDIO_PROFILE_MAX]; static int audio_profile_count = 0; -/* Audio sample structure */ -typedef struct { - char filename[512]; - int16_t *buffer; - int samples; - float volume; -} audio_sample_t; - -typedef struct { - int position; - int active; -} single_step_state_t; - -/* Multi-track seek audio state */ -typedef struct { - int position; - int active; - int duration_samples; - int from_track; - int to_track; - int track_diff; -} multi_seek_state_t; - -/* Drive type specific audio samples */ -typedef struct { - audio_sample_t spindlemotor_start; - audio_sample_t spindlemotor_loop; - audio_sample_t spindlemotor_stop; - /* Individual seek samples for each track count (indexed 0-78 for 1-79 tracks) */ - audio_sample_t seek_up[MAX_SEEK_SAMPLES]; - audio_sample_t seek_down[MAX_SEEK_SAMPLES]; -} drive_audio_samples_t; - /* Dynamic sample storage for each profile */ static drive_audio_samples_t profile_samples[FDD_AUDIO_PROFILE_MAX]; @@ -86,28 +54,112 @@ static multi_seek_state_t seek_state[FDD_NUM][MAX_CONCURRENT_SEEKS] = {}; extern uint64_t motoron[FDD_NUM]; extern char exe_path[2048]; -extern int fdd_get_audio_profile(int drive); - -/* Forward declaration */ -static int16_t *load_wav(const char *filename, int *sample_count); - -# ifdef ENABLE_FDD_LOG -int fdc_do_log = ENABLE_FDD_LOG; +extern uint8_t *rom; +extern uint32_t biosmask; +extern uint32_t biosaddr; +typedef enum { + BIOS_VENDOR_UNKNOWN = 0, + BIOS_VENDOR_AMI, + BIOS_VENDOR_AWARD, + BIOS_VENDOR_PHOENIX, + BIOS_VENDOR_IBM, + BIOS_VENDOR_COMPAQ, + BIOS_VENDOR_OTHER +} bios_vendor_t; + +#ifdef ENABLE_FDD_LOG +int fdd_audio_do_log = ENABLE_FDD_LOG; static void fdd_log(const char *fmt, ...) { va_list ap; - if (fdc_do_log) { + if (fdd_audio_do_log) { va_start(ap, fmt); pclog_ex(fmt, ap); va_end(ap); } } -# else +#else # define fdd_log(fmt, ...) -# endif +#endif + +/* Detect BIOS vendor by scanning ROM for signature strings */ +static bios_vendor_t +fdd_audio_detect_bios_vendor(void) +{ + if (!rom || biosmask == 0) + return BIOS_VENDOR_UNKNOWN; + + /* Search for BIOS vendor strings in ROM */ + for (uint32_t i = 0; i < (biosmask + 1); i++) { + /* AMI BIOS signatures */ + if ((i + 7) < (biosmask + 1)) { + if (memcmp(&rom[i], "AMIBIOS", 7) == 0) { + fdd_log("FDD Audio: Detected AMI BIOS\n"); + return BIOS_VENDOR_AMI; + } + if (memcmp(&rom[i], "American Megatrends", 19) == 0) { + fdd_log("FDD Audio: Detected AMI BIOS (American Megatrends)\n"); + return BIOS_VENDOR_AMI; + } + } + + /* Award BIOS signatures */ + if ((i + 5) < (biosmask + 1)) { + if (memcmp(&rom[i], "Award", 5) == 0) { + fdd_log("FDD Audio: Detected Award BIOS\n"); + return BIOS_VENDOR_AWARD; + } + } + + /* Phoenix BIOS signatures */ + if ((i + 7) < (biosmask + 1)) { + if (memcmp(&rom[i], "Phoenix", 7) == 0) { + fdd_log("FDD Audio: Detected Phoenix BIOS\n"); + return BIOS_VENDOR_PHOENIX; + } + } + + /* IBM BIOS signatures */ + if ((i + 3) < (biosmask + 1)) { + if (memcmp(&rom[i], "IBM", 3) == 0 && (i + 10) < (biosmask + 1)) { + if (memcmp(&rom[i], "IBM CORP", 8) == 0) { + fdd_log("FDD Audio: Detected IBM BIOS\n"); + return BIOS_VENDOR_IBM; + } + } + } + + /* Compaq BIOS signatures */ + if ((i + 6) < (biosmask + 1)) { + if (memcmp(&rom[i], "COMPAQ", 6) == 0) { + fdd_log("FDD Audio: Detected Compaq BIOS\n"); + return BIOS_VENDOR_COMPAQ; + } + } + } + + fdd_log("FDD Audio: BIOS vendor unknown\n"); + return BIOS_VENDOR_UNKNOWN; +} + +/* Determine if this BIOS uses POST-mode FDC seeks */ +static int +fdd_audio_get_bios_vendor(void) +{ + static bios_vendor_t detected_vendor = BIOS_VENDOR_UNKNOWN; + static int detection_done = 0; + + /* Only detect once */ + if (!detection_done) { + detected_vendor = fdd_audio_detect_bios_vendor(); + detection_done = 1; + } + + return detected_vendor; +} /* Logging function for audio profile parameters */ static void @@ -271,13 +323,67 @@ fdd_audio_load_profiles(void) snprintf(key, sizeof(key), "seek_down_%dtrack_volume", track_count); profile->seek_down[track_count - 1].volume = ini_section_get_double(section, key, 1.0); + /* POST mode seek down samples */ + snprintf(key, sizeof(key), "post_seek_down_%dtrack_file", track_count); + filename = ini_section_get_string(section, key, ""); + strncpy(profile->post_seek_down[track_count - 1].filename, filename, + sizeof(profile->post_seek_down[track_count - 1].filename) - 1); + profile->post_seek_down[track_count - 1].filename[sizeof(profile->post_seek_down[track_count - 1].filename) - 1] = '\0'; + + snprintf(key, sizeof(key), "post_seek_down_%dtrack_volume", track_count); + profile->post_seek_down[track_count - 1].volume = ini_section_get_double(section, key, 1.0); + + /* BIOS vendor-specific POST mode seek samples */ + static const char *bios_prefixes[] = { + NULL, /* BIOS_VENDOR_UNKNOWN */ + "amibios", /* BIOS_VENDOR_AMI */ + "award", /* BIOS_VENDOR_AWARD */ + "phoenix", /* BIOS_VENDOR_PHOENIX */ + "ibm", /* BIOS_VENDOR_IBM */ + "compaq", /* BIOS_VENDOR_COMPAQ */ + NULL /* BIOS_VENDOR_OTHER */ + }; + + for (int vendor = 1; vendor < BIOS_VENDOR_COUNT; vendor++) { + if (!bios_prefixes[vendor]) + continue; + + /* BIOS-specific POST mode seek up samples */ + snprintf(key, sizeof(key), "%s_post_seek_up_%dtrack_file", bios_prefixes[vendor], track_count); + filename = ini_section_get_string(section, key, ""); + strncpy(profile->bios_post_seek_up[vendor][track_count - 1].filename, filename, + sizeof(profile->bios_post_seek_up[vendor][track_count - 1].filename) - 1); + profile->bios_post_seek_up[vendor][track_count - 1].filename[sizeof(profile->bios_post_seek_up[vendor][track_count - 1].filename) - 1] = '\0'; + + snprintf(key, sizeof(key), "%s_post_seek_up_%dtrack_volume", bios_prefixes[vendor], track_count); + profile->bios_post_seek_up[vendor][track_count - 1].volume = ini_section_get_double(section, key, 1.0); + + /* BIOS-specific POST mode seek down samples */ + snprintf(key, sizeof(key), "%s_post_seek_down_%dtrack_file", bios_prefixes[vendor], track_count); + filename = ini_section_get_string(section, key, ""); + strncpy(profile->bios_post_seek_down[vendor][track_count - 1].filename, filename, + sizeof(profile->bios_post_seek_down[vendor][track_count - 1].filename) - 1); + profile->bios_post_seek_down[vendor][track_count - 1].filename[sizeof(profile->bios_post_seek_down[vendor][track_count - 1].filename) - 1] = '\0'; + + snprintf(key, sizeof(key), "%s_post_seek_down_%dtrack_volume", bios_prefixes[vendor], track_count); + profile->bios_post_seek_down[vendor][track_count - 1].volume = ini_section_get_double(section, key, 1.0); + + /* BIOS-specific POST mode seek time in milliseconds */ + snprintf(key, sizeof(key), "%s_post_seek_%dtrack_time_ms", bios_prefixes[vendor], track_count); + profile->bios_post_seek_time_ms[vendor][track_count - 1] = ini_section_get_double(section, key, 0.0); + } + /* Seek time in milliseconds - used for FDC timing, not sample playback */ snprintf(key, sizeof(key), "seek_%dtrack_time_ms", track_count); profile->seek_time_ms[track_count - 1] = ini_section_get_double(section, key, 6.0 * track_count); + + /* POST mode seek time in milliseconds */ + snprintf(key, sizeof(key), "post_seek_%dtrack_time_ms", track_count); + profile->post_seek_time_ms[track_count - 1] = ini_section_get_double(section, key, 0.0); } /* Load timing configurations */ - profile->total_tracks = ini_section_get_int(section, "total_tracks", 80); + profile->total_tracks = ini_section_get_int(section, "total_tracks", 0); audio_profile_count++; } @@ -291,7 +397,7 @@ fdd_audio_load_profiles(void) void load_profile_samples(int profile_id) { - if (profile_id <= 0 || profile_id >= audio_profile_count) + if (profile_id < 0 || profile_id >= audio_profile_count) return; fdd_audio_profile_config_t *config = &audio_profiles[profile_id]; @@ -304,7 +410,7 @@ load_profile_samples(int profile_id) if (samples->spindlemotor_start.buffer == NULL && config->spindlemotor_start.filename[0]) { strcpy(samples->spindlemotor_start.filename, config->spindlemotor_start.filename); samples->spindlemotor_start.volume = config->spindlemotor_start.volume; - samples->spindlemotor_start.buffer = load_wav(config->spindlemotor_start.filename, + samples->spindlemotor_start.buffer = sound_load_wav(config->spindlemotor_start.filename, &samples->spindlemotor_start.samples); if (samples->spindlemotor_start.buffer) { fdd_log(" Loaded spindlemotor_start: %s (%d samples, volume %.2f)\n", @@ -320,7 +426,7 @@ load_profile_samples(int profile_id) if (samples->spindlemotor_loop.buffer == NULL && config->spindlemotor_loop.filename[0]) { strcpy(samples->spindlemotor_loop.filename, config->spindlemotor_loop.filename); samples->spindlemotor_loop.volume = config->spindlemotor_loop.volume; - samples->spindlemotor_loop.buffer = load_wav(config->spindlemotor_loop.filename, + samples->spindlemotor_loop.buffer = sound_load_wav(config->spindlemotor_loop.filename, &samples->spindlemotor_loop.samples); if (samples->spindlemotor_loop.buffer) { fdd_log(" Loaded spindlemotor_loop: %s (%d samples, volume %.2f)\n", @@ -336,7 +442,7 @@ load_profile_samples(int profile_id) if (samples->spindlemotor_stop.buffer == NULL && config->spindlemotor_stop.filename[0]) { strcpy(samples->spindlemotor_stop.filename, config->spindlemotor_stop.filename); samples->spindlemotor_stop.volume = config->spindlemotor_stop.volume; - samples->spindlemotor_stop.buffer = load_wav(config->spindlemotor_stop.filename, + samples->spindlemotor_stop.buffer = sound_load_wav(config->spindlemotor_stop.filename, &samples->spindlemotor_stop.samples); if (samples->spindlemotor_stop.buffer) { fdd_log(" Loaded spindlemotor_stop: %s (%d samples, volume %.2f)\n", @@ -358,11 +464,11 @@ load_profile_samples(int profile_id) if (samples->seek_up[idx].buffer == NULL && config->seek_up[idx].filename[0]) { strcpy(samples->seek_up[idx].filename, config->seek_up[idx].filename); samples->seek_up[idx].volume = config->seek_up[idx].volume; - samples->seek_up[idx].buffer = load_wav(config->seek_up[idx].filename, + samples->seek_up[idx].buffer = sound_load_wav(config->seek_up[idx].filename, &samples->seek_up[idx].samples); if (samples->seek_up[idx].buffer) { fdd_log(" Loaded seek_up[%d]: %s (%d samples, volume %.2f)\n", - track_count, config->seek_up[idx].filename, + idx, config->seek_up[idx].filename, samples->seek_up[idx].samples, config->seek_up[idx].volume); } } @@ -371,14 +477,80 @@ load_profile_samples(int profile_id) if (samples->seek_down[idx].buffer == NULL && config->seek_down[idx].filename[0]) { strcpy(samples->seek_down[idx].filename, config->seek_down[idx].filename); samples->seek_down[idx].volume = config->seek_down[idx].volume; - samples->seek_down[idx].buffer = load_wav(config->seek_down[idx].filename, + samples->seek_down[idx].buffer = sound_load_wav(config->seek_down[idx].filename, &samples->seek_down[idx].samples); if (samples->seek_down[idx].buffer) { fdd_log(" Loaded seek_down[%d]: %s (%d samples, volume %.2f)\n", - track_count, config->seek_down[idx].filename, + idx, config->seek_down[idx].filename, samples->seek_down[idx].samples, config->seek_down[idx].volume); } } + + /* Load POST mode seek samples if configured */ + if (config->post_seek_up[idx].filename[0]) { + if (samples->post_seek_up[idx].buffer == NULL) { + strcpy(samples->post_seek_up[idx].filename, config->post_seek_up[idx].filename); + samples->post_seek_up[idx].volume = config->post_seek_up[idx].volume; + samples->post_seek_up[idx].buffer = sound_load_wav(config->post_seek_up[idx].filename, + &samples->post_seek_up[idx].samples); + if (samples->post_seek_up[idx].buffer) { + fdd_log(" Loaded POST seek_up[%d] (%d-track): %s (%d samples, volume %.2f)\n", + idx, track_count, config->post_seek_up[idx].filename, + samples->post_seek_up[idx].samples, config->post_seek_up[idx].volume); + } + } + } + + if (config->post_seek_down[idx].filename[0]) { + if (samples->post_seek_down[idx].buffer == NULL) { + strcpy(samples->post_seek_down[idx].filename, config->post_seek_down[idx].filename); + samples->post_seek_down[idx].volume = config->post_seek_down[idx].volume; + samples->post_seek_down[idx].buffer = sound_load_wav(config->post_seek_down[idx].filename, + &samples->post_seek_down[idx].samples); + if (samples->post_seek_down[idx].buffer) { + fdd_log(" Loaded POST seek_down[%d] (%d-track): %s (%d samples, volume %.2f)\n", + idx, track_count, config->post_seek_down[idx].filename, + samples->post_seek_down[idx].samples, config->post_seek_down[idx].volume); + } + } + } + +#ifdef ENABLE_FDD_LOG + /* Load BIOS vendor-specific POST mode seek samples if configured */ + static const char *bios_names[] = { + "UNKNOWN", "AMI", "AWARD", "PHOENIX", "IBM", "COMPAQ", "OTHER" + }; +#endif + + for (int vendor = 1; vendor < BIOS_VENDOR_COUNT; vendor++) { + if (config->bios_post_seek_up[vendor][idx].filename[0]) { + if (samples->bios_post_seek_up[vendor][idx].buffer == NULL) { + strcpy(samples->bios_post_seek_up[vendor][idx].filename, config->bios_post_seek_up[vendor][idx].filename); + samples->bios_post_seek_up[vendor][idx].volume = config->bios_post_seek_up[vendor][idx].volume; + samples->bios_post_seek_up[vendor][idx].buffer = sound_load_wav(config->bios_post_seek_up[vendor][idx].filename, + &samples->bios_post_seek_up[vendor][idx].samples); + if (samples->bios_post_seek_up[vendor][idx].buffer) { + fdd_log(" Loaded %s POST seek_up[%d] (%d-track): %s (%d samples, volume %.2f)\n", + bios_names[vendor], idx, track_count, config->bios_post_seek_up[vendor][idx].filename, + samples->bios_post_seek_up[vendor][idx].samples, config->bios_post_seek_up[vendor][idx].volume); + } + } + } + + if (config->bios_post_seek_down[vendor][idx].filename[0]) { + if (samples->bios_post_seek_down[vendor][idx].buffer == NULL) { + strcpy(samples->bios_post_seek_down[vendor][idx].filename, config->bios_post_seek_down[vendor][idx].filename); + samples->bios_post_seek_down[vendor][idx].volume = config->bios_post_seek_down[vendor][idx].volume; + samples->bios_post_seek_down[vendor][idx].buffer = sound_load_wav(config->bios_post_seek_down[vendor][idx].filename, + &samples->bios_post_seek_down[vendor][idx].samples); + if (samples->bios_post_seek_down[vendor][idx].buffer) { + fdd_log(" Loaded %s POST seek_down[%d] (%d-track): %s (%d samples, volume %.2f)\n", + bios_names[vendor], idx, track_count, config->bios_post_seek_down[vendor][idx].filename, + samples->bios_post_seek_down[vendor][idx].samples, config->bios_post_seek_down[vendor][idx].volume); + } + } + } + } } } @@ -444,7 +616,7 @@ double fdd_audio_get_seek_time(int drive, int track_count, int is_seek_down) { int profile_id = fdd_get_audio_profile(drive); - if (profile_id <= 0 || profile_id >= audio_profile_count) { + if (profile_id < 0 || profile_id >= audio_profile_count) { return 0; } @@ -461,6 +633,21 @@ fdd_audio_get_seek_time(int drive, int track_count, int is_seek_down) /* Return configured seek time in microseconds */ if (track_count > 0 && track_count <= MAX_SEEK_SAMPLES) { + /* In POST mode, check for BIOS-specific timing first */ + if (fdd_get_boot_status() == BIOS_BOOT_POST) { + int bios_vendor = fdd_audio_get_bios_vendor(); + + /* Check BIOS vendor-specific timing first */ + if (bios_vendor > 0 && bios_vendor < BIOS_VENDOR_COUNT && + profile->bios_post_seek_time_ms[bios_vendor][track_count - 1] > 0.0) { + return profile->bios_post_seek_time_ms[bios_vendor][track_count - 1] * 1000.0; + } + + /* Fall back to generic POST timing */ + if (profile->post_seek_time_ms[track_count - 1] > 0.0) { + return profile->post_seek_time_ms[track_count - 1] * 1000.0; + } + } return profile->seek_time_ms[track_count - 1] * 1000.0; } @@ -489,6 +676,7 @@ fdd_audio_init(void) seek_state[i][j].from_track = -1; seek_state[i][j].to_track = -1; seek_state[i][j].track_diff = 0; + seek_state[i][j].sample_to_play = NULL; } } @@ -546,6 +734,30 @@ fdd_audio_close(void) samples->seek_down[track_count].buffer = NULL; samples->seek_down[track_count].samples = 0; } + if (samples->post_seek_up[track_count].buffer) { + free(samples->post_seek_up[track_count].buffer); + samples->post_seek_up[track_count].buffer = NULL; + samples->post_seek_up[track_count].samples = 0; + } + if (samples->post_seek_down[track_count].buffer) { + free(samples->post_seek_down[track_count].buffer); + samples->post_seek_down[track_count].buffer = NULL; + samples->post_seek_down[track_count].samples = 0; + } + + /* Free BIOS vendor-specific POST seek samples */ + for (int vendor = 0; vendor < BIOS_VENDOR_COUNT; vendor++) { + if (samples->bios_post_seek_up[vendor][track_count].buffer) { + free(samples->bios_post_seek_up[vendor][track_count].buffer); + samples->bios_post_seek_up[vendor][track_count].buffer = NULL; + samples->bios_post_seek_up[vendor][track_count].samples = 0; + } + if (samples->bios_post_seek_down[vendor][track_count].buffer) { + free(samples->bios_post_seek_down[vendor][track_count].buffer); + samples->bios_post_seek_down[vendor][track_count].buffer = NULL; + samples->bios_post_seek_down[vendor][track_count].samples = 0; + } + } } } @@ -629,16 +841,81 @@ fdd_audio_play_multi_track_seek(int drive, int from_track, int to_track) track_diff = max_seek_tracks; } - /* Get the appropriate seek sample */ - int idx = track_diff - 1; - audio_sample_t *sample_to_use = is_seek_down ? &samples->seek_down[idx] : &samples->seek_up[idx]; + int boot_status = fdd_get_boot_status(); + int bios_vendor = fdd_audio_get_bios_vendor(); + int idx = track_diff - 1; + int real_track_diff = to_track - from_track; + audio_sample_t *sample_to_use = NULL; + + if (boot_status == BIOS_BOOT_POST) { + if (bios_vendor == BIOS_VENDOR_AMI) { + /* AMI BIOS POST mode: use AMI-specific samples if available */ + + /* AMI BIOS quirk: for single-track seeks down (except 10->9), do not play audio */ + if (real_track_diff == -1 && (from_track != 10 || to_track != 9)) { + fdd_log("FDD Audio Drive %d: AMI BIOS quirk: for single-track seeks down (except 10->9), do not play audio\n", drive); + return; + } + + /* For 10->9 seek, use the 1-track sample (which should be the 10-0 sound) */ + sample_to_use = is_seek_down ? &samples->bios_post_seek_down[bios_vendor][idx] : &samples->bios_post_seek_up[bios_vendor][idx]; + + if (sample_to_use->buffer && sample_to_use->samples > 0) { + fdd_log("FDD Audio Drive %d: Using AMI BIOS POST mode seek sample (idx=%d, %s)\n", + drive, idx, is_seek_down ? "DOWN" : "UP"); + } else { + /* Fall back to generic POST sample */ + sample_to_use = is_seek_down ? &samples->post_seek_down[idx] : &samples->post_seek_up[idx]; + if (sample_to_use->buffer && sample_to_use->samples > 0) { + fdd_log("FDD Audio Drive %d: AMI BIOS sample not available, using generic POST sample (idx=%d, %s)\n", + drive, idx, is_seek_down ? "DOWN" : "UP"); + } else { + /* Fall back to normal sample */ + fdd_log("FDD Audio Drive %d: POST sample not available, using normal sample\n", drive); + sample_to_use = is_seek_down ? &samples->seek_down[idx] : &samples->seek_up[idx]; + } + } + } else if (bios_vendor > 0 && bios_vendor < BIOS_VENDOR_COUNT) { + /* Other known BIOS vendors: try vendor-specific samples first */ + sample_to_use = is_seek_down ? &samples->bios_post_seek_down[bios_vendor][idx] : &samples->bios_post_seek_up[bios_vendor][idx]; + + if (sample_to_use->buffer && sample_to_use->samples > 0) { + fdd_log("FDD Audio Drive %d: Using BIOS vendor %d POST mode seek sample (idx=%d, %s)\n", + drive, bios_vendor, idx, is_seek_down ? "DOWN" : "UP"); + } else { + /* Fall back to generic POST sample */ + sample_to_use = is_seek_down ? &samples->post_seek_down[idx] : &samples->post_seek_up[idx]; + if (sample_to_use->buffer && sample_to_use->samples > 0) { + fdd_log("FDD Audio Drive %d: BIOS-specific sample not available, using generic POST sample (idx=%d, %s)\n", + drive, idx, is_seek_down ? "DOWN" : "UP"); + } else { + /* Fall back to normal sample */ + fdd_log("FDD Audio Drive %d: POST sample not available, using normal sample\n", drive); + sample_to_use = is_seek_down ? &samples->seek_down[idx] : &samples->seek_up[idx]; + } + } + } else { + /* Unknown BIOS vendor POST mode */ + sample_to_use = is_seek_down ? &samples->post_seek_down[idx] : &samples->post_seek_up[idx]; + if (!sample_to_use->buffer || sample_to_use->samples == 0) { + fdd_log("FDD Audio Drive %d: POST sample not available, using normal sample\n", drive); + sample_to_use = is_seek_down ? &samples->seek_down[idx] : &samples->seek_up[idx]; + } else { + fdd_log("FDD Audio Drive %d: Using POST mode seek sample (idx=%d, %s)\n", + drive, idx, is_seek_down ? "DOWN" : "UP"); + } + } + } else { + /* Use normal samples */ + sample_to_use = is_seek_down ? &samples->seek_down[idx] : &samples->seek_up[idx]; + } /* Only proceed if we have the appropriate sample */ if (!sample_to_use || !sample_to_use->buffer || sample_to_use->samples == 0) return; - fdd_log("FDD Audio Drive %d: Multi-track seek %d -> %d (%d tracks, %s)\n", - drive, from_track, to_track, track_diff, is_seek_down ? "DOWN" : "UP"); + fdd_log("FDD Audio Drive %d: Multi-track seek %d -> %d (%d tracks, %s, POST=%d)\n", + drive, from_track, to_track, track_diff, is_seek_down ? "DOWN" : "UP", boot_status); /* Find an available seek slot */ int slot = -1; @@ -662,97 +939,12 @@ fdd_audio_play_multi_track_seek(int drive, int from_track, int to_track) seek_state[drive][slot].from_track = from_track; seek_state[drive][slot].to_track = to_track; seek_state[drive][slot].track_diff = track_diff; + seek_state[drive][slot].sample_to_play = sample_to_use; fdd_log("FDD Audio Drive %d: Started seek in slot %d, duration %d samples\n", drive, slot, sample_to_use->samples); } -static int16_t * -load_wav(const char *filename, int *sample_count) -{ - if ((filename == NULL) || (strlen(filename) == 0)) - return NULL; - - if (strstr(filename, "..") != NULL) - return NULL; - - FILE *f = asset_fopen(filename, "rb"); - if (f == NULL) { - fdd_log("FDD Audio: Failed to open WAV file: %s\n", filename); - return NULL; - } - - wav_header_t hdr; - if (fread(&hdr, sizeof(hdr), 1, f) != 1) { - fdd_log("FDD Audio: Failed to read WAV header from: %s\n", filename); - fclose(f); - return NULL; - } - - if (memcmp(hdr.riff, "RIFF", 4) || memcmp(hdr.wave, "WAVE", 4) || memcmp(hdr.fmt, "fmt ", 4) || memcmp(hdr.data, "data", 4)) { - fdd_log("FDD Audio: Invalid WAV format in file: %s\n", filename); - fclose(f); - return NULL; - } - - /* Accept both mono and stereo, 16-bit PCM */ - if (hdr.audio_format != 1 || hdr.bits_per_sample != 16 || (hdr.num_channels != 1 && hdr.num_channels != 2)) { - fdd_log("FDD Audio: Unsupported WAV format in %s (format: %d, bits: %d, channels: %d)\n", - filename, hdr.audio_format, hdr.bits_per_sample, hdr.num_channels); - fclose(f); - return NULL; - } - - int input_samples = hdr.data_size / 2; /* 2 bytes per sample */ - int16_t *input_data = malloc(hdr.data_size); - if (!input_data) { - fdd_log("FDD Audio: Failed to allocate memory for WAV data: %s\n", filename); - fclose(f); - return NULL; - } - - if (fread(input_data, 1, hdr.data_size, f) != hdr.data_size) { - fdd_log("FDD Audio: Failed to read WAV data from: %s\n", filename); - free(input_data); - fclose(f); - return NULL; - } - fclose(f); - - int16_t *output_data; - int output_samples; - - if (hdr.num_channels == 1) { - /* Convert mono to stereo */ - output_samples = input_samples; /* Number of stereo sample pairs */ - output_data = malloc(input_samples * 2 * sizeof(int16_t)); /* Allocate for stereo */ - if (!output_data) { - fdd_log("FDD Audio: Failed to allocate stereo conversion buffer for: %s\n", filename); - free(input_data); - return NULL; - } - - /* Convert mono to stereo by duplicating each sample */ - for (int i = 0; i < input_samples; i++) { - output_data[i * 2] = input_data[i]; /* Left channel */ - output_data[i * 2 + 1] = input_data[i]; /* Right channel */ - } - - free(input_data); - fdd_log("FDD Audio: Loaded %s (mono->stereo, %d samples)\n", filename, output_samples); - } else { - /* Already stereo */ - output_data = input_data; - output_samples = input_samples / 2; /* Number of stereo sample pairs */ - fdd_log("FDD Audio: Loaded %s (stereo, %d samples)\n", filename, output_samples); - } - - if (sample_count) - *sample_count = output_samples; - - return output_data; -} - void fdd_audio_callback(int16_t *buffer, int length) { @@ -867,30 +1059,26 @@ fdd_audio_callback(int16_t *buffer, int length) if (!seek_state[drive][slot].active) continue; - int track_diff = seek_state[drive][slot].track_diff; - if (track_diff > 0 && track_diff <= MAX_SEEK_SAMPLES) { - int idx = track_diff - 1; - int is_seek_down = (seek_state[drive][slot].to_track < seek_state[drive][slot].from_track); - audio_sample_t *seek_sample = is_seek_down ? &samples->seek_down[idx] : &samples->seek_up[idx]; - - if (seek_sample && seek_sample->buffer && seek_state[drive][slot].position < seek_sample->samples) { - /* Mix seek sound with existing audio */ - float seek_left = (float) seek_sample->buffer[seek_state[drive][slot].position * 2] / 131072.0f * seek_sample->volume; - float seek_right = (float) seek_sample->buffer[seek_state[drive][slot].position * 2 + 1] / 131072.0f * seek_sample->volume; - - left_sample += seek_left; - right_sample += seek_right; - - seek_state[drive][slot].position++; - } else { - /* Seek sound finished */ - seek_state[drive][slot].active = 0; - seek_state[drive][slot].position = 0; - seek_state[drive][slot].duration_samples = 0; - seek_state[drive][slot].from_track = -1; - seek_state[drive][slot].to_track = -1; - seek_state[drive][slot].track_diff = 0; - } + audio_sample_t *seek_sample = seek_state[drive][slot].sample_to_play; + + if (seek_sample && seek_sample->buffer && seek_state[drive][slot].position < seek_sample->samples) { + /* Mix seek sound with existing audio */ + float seek_left = (float) seek_sample->buffer[seek_state[drive][slot].position * 2] / 131072.0f * seek_sample->volume; + float seek_right = (float) seek_sample->buffer[seek_state[drive][slot].position * 2 + 1] / 131072.0f * seek_sample->volume; + + left_sample += seek_left; + right_sample += seek_right; + + seek_state[drive][slot].position++; + } else { + /* Seek sound finished */ + seek_state[drive][slot].active = 0; + seek_state[drive][slot].position = 0; + seek_state[drive][slot].duration_samples = 0; + seek_state[drive][slot].from_track = -1; + seek_state[drive][slot].to_track = -1; + seek_state[drive][slot].track_diff = 0; + seek_state[drive][slot].sample_to_play = NULL; } } @@ -983,30 +1171,26 @@ fdd_audio_callback(int16_t *buffer, int length) if (!seek_state[drive][slot].active) continue; - int track_diff = seek_state[drive][slot].track_diff; - if (track_diff > 0 && track_diff <= MAX_SEEK_SAMPLES) { - int idx = track_diff - 1; - int is_seek_down = (seek_state[drive][slot].to_track < seek_state[drive][slot].from_track); - audio_sample_t *seek_sample = is_seek_down ? &samples->seek_down[idx] : &samples->seek_up[idx]; - - if (seek_sample && seek_sample->buffer && seek_state[drive][slot].position < seek_sample->samples) { - /* Mix seek sound with existing audio */ - int16_t seek_left = (int16_t) ((float) seek_sample->buffer[seek_state[drive][slot].position * 2] / 4.0f * seek_sample->volume); - int16_t seek_right = (int16_t) ((float) seek_sample->buffer[seek_state[drive][slot].position * 2 + 1] / 4.0f * seek_sample->volume); - - left_sample += seek_left; - right_sample += seek_right; - - seek_state[drive][slot].position++; - } else { - /* Seek sound finished */ - seek_state[drive][slot].active = 0; - seek_state[drive][slot].position = 0; - seek_state[drive][slot].duration_samples = 0; - seek_state[drive][slot].from_track = -1; - seek_state[drive][slot].to_track = -1; - seek_state[drive][slot].track_diff = 0; - } + audio_sample_t *seek_sample = seek_state[drive][slot].sample_to_play; + + if (seek_sample && seek_sample->buffer && seek_state[drive][slot].position < seek_sample->samples) { + /* Mix seek sound with existing audio */ + int16_t seek_left = (int16_t) ((float) seek_sample->buffer[seek_state[drive][slot].position * 2] / 4.0f * seek_sample->volume); + int16_t seek_right = (int16_t) ((float) seek_sample->buffer[seek_state[drive][slot].position * 2 + 1] / 4.0f * seek_sample->volume); + + left_sample += seek_left; + right_sample += seek_right; + + seek_state[drive][slot].position++; + } else { + /* Seek sound finished */ + seek_state[drive][slot].active = 0; + seek_state[drive][slot].position = 0; + seek_state[drive][slot].duration_samples = 0; + seek_state[drive][slot].from_track = -1; + seek_state[drive][slot].to_track = -1; + seek_state[drive][slot].track_diff = 0; + seek_state[drive][slot].sample_to_play = NULL; } } diff --git a/src/floppy/fdd_pcjs.c b/src/floppy/fdd_pcjs.c index 2193048c6e3..b1494cd383e 100644 --- a/src/floppy/fdd_pcjs.c +++ b/src/floppy/fdd_pcjs.c @@ -18,11 +18,7 @@ #include #include #include -#ifndef _MSC_VER #include -#else -#include -#endif #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/timer.h> diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 12eb5dbb5b6..d32e13895da 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -47,7 +47,7 @@ /* Recently used images */ #define MAX_PREV_IMAGES 10 -#define MAX_IMAGE_PATH_LEN 2048 +#define MAX_IMAGE_PATH_LEN 4096 /* Max UUID Length */ #define MAX_UUID_LEN 64 @@ -159,9 +159,10 @@ extern int confirm_exit_cmdl; /* (O) do not ask for confirmation on quit if set extern uint64_t unique_id; extern uint64_t source_hwnd; #endif -extern char rom_path[1024]; /* (O) full path to ROMs */ -extern char log_path[1024]; /* (O) full path of logfile */ -extern char vm_name[1024]; /* (O) display name of the VM */ +extern char rom_path[1024]; /* (O) full path to ROMs */ +extern char asset_path[1024]; /* (O) full path to assets */ +extern char log_path[1024]; /* (O) full path of logfile */ +extern char vm_name[1024]; /* (O) display name of the VM */ #ifdef USE_INSTRUMENT extern uint8_t instru_enabled; extern uint64_t instru_run_ms; @@ -330,7 +331,7 @@ struct accelKey { char desc[64]; char seq[64]; }; -#define NUM_ACCELS 9 +#define NUM_ACCELS 14 extern struct accelKey acc_keys[NUM_ACCELS]; extern struct accelKey def_acc_keys[NUM_ACCELS]; extern int FindAccelerator(const char *name); diff --git a/src/include/86box/cartridge.h b/src/include/86box/cartridge.h index 3afe1c3fcf8..66fa34e1a84 100644 --- a/src/include/86box/cartridge.h +++ b/src/include/86box/cartridge.h @@ -21,7 +21,7 @@ extern "C" { #define CART_IMAGE_HISTORY 10 -extern char cart_fns[2][512]; +extern char cart_fns[2][MAX_IMAGE_PATH_LEN]; extern char *cart_image_history[2][CART_IMAGE_HISTORY]; extern void cart_load(int drive, char *fn); diff --git a/src/include/86box/cassette.h b/src/include/86box/cassette.h index dc85bfc269a..82aebeef6a2 100644 --- a/src/include/86box/cassette.h +++ b/src/include/86box/cassette.h @@ -157,7 +157,7 @@ void pc_cas_advance(pc_cassette_t *cas); extern pc_cassette_t *cassette; -extern char cassette_fname[512]; +extern char cassette_fname[MAX_IMAGE_PATH_LEN]; extern char cassette_mode[512]; extern char * cassette_image_history[CASSETTE_IMAGE_HISTORY]; extern unsigned long cassette_pos; diff --git a/src/include/86box/cdrom.h b/src/include/86box/cdrom.h index 409e303bc25..fb157ba6611 100644 --- a/src/include/86box/cdrom.h +++ b/src/include/86box/cdrom.h @@ -201,6 +201,7 @@ static const struct cdrom_drive_types_s { { "NEC", "CD-ROM DRIVE:211", "1.00", "nec_211", BUS_TYPE_SCSI, 2, 3, 36, 0, 0, { -1, -1, -1, -1 } }, /* The speed of the following two is guesswork based on the CDR-400. */ { "NEC", "CD-ROM DRIVE:464", "1.05", "nec_464", BUS_TYPE_SCSI, 2, 3, 36, 0, 0, { -1, -1, -1, -1 } }, + { "NEC", "CD-ROM DRIVE:900", "2.5a", "nec_900", BUS_TYPE_SCSI, 2, 4, 36, 0, 0, { -1, -1, -1, -1 } }, /* The speed of the following two is guesswork based on the name. */ { "ShinaKen", "CD-ROM DM-3x1S", "1.04", "shinaken_3x1s", BUS_TYPE_SCSI, 1, 3, 36, 0, 0, { -1, -1, -1, -1 } }, { "SONY", "CD-ROM CDU-541", "1.0i", "sony_541", BUS_TYPE_SCSI, 1, 1, 36, 1, 0, { -1, -1, -1, -1 } }, @@ -209,7 +210,10 @@ static const struct cdrom_drive_types_s { { "PHILIPS", "CDD2600", "1.07", "philips_2600", BUS_TYPE_SCSI, 2, 6, 36, 0, 0, { -1, -1, -1, -1 } }, /* NOTE: The real thing is a CD changer drive! */ { "PIONEER", "CD-ROM DRM-604X", "2403", "pioneer_604x", BUS_TYPE_SCSI, 2, 4, 47, 0, 0, { -1, -1, -1, -1 } }, + { "PLEXTOR", "CD-ROM PX-12CS", "1.04", "plextor_12cs", BUS_TYPE_SCSI, 2, 12, 36, 1, 0, { -1, -1, -1, -1 } }, + { "PLEXTOR", "CD-ROM PX-12TS", "1.01", "plextor_12ts", BUS_TYPE_SCSI, 2, 12, 36, 0, 0, { -1, -1, -1, -1 } }, { "PLEXTOR", "CD-ROM PX-32TS", "1.03", "plextor_32ts", BUS_TYPE_SCSI, 2, 32, 36, 0, 0, { -1, -1, -1, -1 } }, + { "PLEXTOR", "CD-ROM PX-83CS", "1.01", "plextor_83cs", BUS_TYPE_SCSI, 2, 8, 36, 1, 0, { -1, -1, -1, -1 } }, /* The speed of the following two is guesswork based on the R55S. */ { "TEAC", "CD 50", "1.00", "teac_50", BUS_TYPE_SCSI, 2, 4, 36, 1, 0, { -1, -1, -1, -1 } }, { "TEAC", "CD-ROM R55S", "1.0R", "teac_55s", BUS_TYPE_SCSI, 2, 4, 36, 0, 0, { -1, -1, -1, -1 } }, @@ -229,6 +233,7 @@ static const struct cdrom_drive_types_s { { "TOSHIBA", "CD-ROM DRIVE:XM", "3433", "toshiba_xm", BUS_TYPE_SCSI, 2, 2, 96, 0, 0, { -1, -1, -1, -1 } }, /* Tray. */ { "TOSHIBA", "CD-ROM XM-3201B", "3232", "toshiba_3201b", BUS_TYPE_SCSI, 1, 1, 96, 1, 0, { -1, -1, -1, -1 } }, /* Caddy. */ { "TOSHIBA", "CD-ROM XM-3301TA", "0272", "toshiba_3301ta", BUS_TYPE_SCSI, 2, 2, 96, 0, 0, { -1, -1, -1, -1 } }, /* Tray. */ + { "TOSHIBA", "CD-ROM XM-3701B", "0236", "toshiba_3701b", BUS_TYPE_SCSI, 2, 6, 96, 0, 0, { -1, -1, -1, -1 } }, /* Tray. */ { "TOSHIBA", "CD-ROM XM-5701TA", "3136", "toshiba_5701a", BUS_TYPE_SCSI, 2, 12, 96, 0, 0, { -1, -1, -1, -1 } }, /* Tray. */ { "TOSHIBA", "DVD-ROM SD-M1401", "1008", "toshiba_m1401", BUS_TYPE_SCSI, 2, 40, 96, 0, 1, { -1, -1, -1, -1 } }, /* Tray. */ { "MATSHITA", "CR-562", "0.75", "cr562", BUS_TYPE_MKE , 0, 2, 0, 0, 0, { -1, -1, -1, -1 } }, @@ -318,8 +323,8 @@ typedef struct cdrom { void *priv; - char image_path[1024]; - char prev_image_path[1280]; + char image_path[MAX_IMAGE_PATH_LEN]; + char prev_image_path[MAX_IMAGE_PATH_LEN + 256]; uint32_t sound_on; uint32_t cdrom_capacity; @@ -476,6 +481,8 @@ extern void cdrom_close(void); extern void cdrom_insert(const uint8_t id); extern void cdrom_exit(const uint8_t id); extern int cdrom_is_empty(const uint8_t id); +extern int cdrom_is_playing(const uint8_t id); +extern int cdrom_is_paused(const uint8_t id); extern void cdrom_eject(const uint8_t id); extern void cdrom_reload(const uint8_t id); diff --git a/src/include/86box/device.h b/src/include/86box/device.h index b6e78f41c8f..58edab35cab 100644 --- a/src/include/86box/device.h +++ b/src/include/86box/device.h @@ -206,6 +206,7 @@ extern void *device_get_priv(const device_t *dev); extern int device_available(const device_t *dev); extern void device_speed_changed(void); extern void device_force_redraw(void); +extern const char *device_get_bus_name(const device_t *dev); extern void device_get_name(const device_t *dev, int bus, char *name); extern int device_has_config(const device_t *dev); diff --git a/src/include/86box/fdd.h b/src/include/86box/fdd.h index b10c3485489..5e526ab6dbc 100644 --- a/src/include/86box/fdd.h +++ b/src/include/86box/fdd.h @@ -24,6 +24,13 @@ #define FDD_NUM 4 #define FLOPPY_IMAGE_HISTORY 10 #define SEEK_RECALIBRATE -999 +#define DEFAULT_SEEK_TIME_MS 10.0 + +/* BIOS boot status - used to detect POST vs normal operation */ +typedef enum { + BIOS_BOOT_POST = 0, /* System is in POST (Power-On Self Test) */ + BIOS_BOOT_NORMAL = 1 /* POST complete, normal operation */ +} bios_boot_status_t; #ifdef __cplusplus extern "C" { @@ -89,7 +96,7 @@ typedef struct DRIVE { } DRIVE; extern DRIVE drives[FDD_NUM]; -extern char floppyfns[FDD_NUM][512]; +extern char floppyfns[FDD_NUM][MAX_IMAGE_PATH_LEN]; extern char *fdd_image_history[FDD_NUM][FLOPPY_IMAGE_HISTORY]; extern pc_timer_t fdd_poll_time[FDD_NUM]; extern int ui_writeprot[FDD_NUM]; @@ -117,6 +124,12 @@ extern int fdd_hole(int drive); extern void fdd_stop(int drive); extern void fdd_do_writeback(int drive); +/* BIOS boot status functions */ +extern bios_boot_status_t fdd_get_boot_status(void); +extern void fdd_set_boot_status(bios_boot_status_t status); +extern void fdd_boot_status_reset(void); +extern int fdd_is_post_complete(void); + extern int motorspin; extern uint64_t motoron[FDD_NUM]; diff --git a/src/include/86box/fdd_audio.h b/src/include/86box/fdd_audio.h index 1d1b52d1494..ac6f225be73 100644 --- a/src/include/86box/fdd_audio.h +++ b/src/include/86box/fdd_audio.h @@ -16,6 +16,7 @@ #define EMU_FDD_AUDIO_H #include +#include <86box/fdd.h> #ifdef __cplusplus extern "C" { @@ -29,6 +30,9 @@ extern "C" { /* Maximum number of simultaneous seek sounds per drive */ #define MAX_CONCURRENT_SEEKS 8 +/* Number of BIOS vendors (for BIOS-specific samples) */ +#define BIOS_VENDOR_COUNT 7 + /* Audio sample configuration structure */ typedef struct { char filename[512]; @@ -45,7 +49,15 @@ typedef struct { audio_sample_config_t spindlemotor_stop; audio_sample_config_t seek_up[MAX_SEEK_SAMPLES]; audio_sample_config_t seek_down[MAX_SEEK_SAMPLES]; - double seek_time_ms[MAX_SEEK_SAMPLES]; /* Seek time in milliseconds for each track count */ + audio_sample_config_t post_seek_up[MAX_SEEK_SAMPLES]; + audio_sample_config_t post_seek_down[MAX_SEEK_SAMPLES]; + /* BIOS vendor-specific POST seek samples [vendor][track] */ + audio_sample_config_t bios_post_seek_up[BIOS_VENDOR_COUNT][MAX_SEEK_SAMPLES]; + audio_sample_config_t bios_post_seek_down[BIOS_VENDOR_COUNT][MAX_SEEK_SAMPLES]; + double seek_time_ms[MAX_SEEK_SAMPLES]; + double post_seek_time_ms[MAX_SEEK_SAMPLES]; + /* BIOS vendor-specific POST seek times [vendor][track] */ + double bios_post_seek_time_ms[BIOS_VENDOR_COUNT][MAX_SEEK_SAMPLES]; int total_tracks; /* 40 or 80 */ } fdd_audio_profile_config_t; @@ -59,22 +71,44 @@ typedef enum { MOTOR_STATE_STOPPING } motor_state_t; -/* WAV header structure */ +/* Audio sample structure */ +typedef struct { + char filename[512]; + int16_t *buffer; + int samples; + float volume; +} audio_sample_t; + +typedef struct { + int position; + int active; +} single_step_state_t; + +/* Multi-track seek audio state */ +typedef struct { + int position; + int active; + int duration_samples; + int from_track; + int to_track; + int track_diff; + audio_sample_t *sample_to_play; +} multi_seek_state_t; + +/* Drive type specific audio samples */ typedef struct { - char riff[4]; - uint32_t size; - char wave[4]; - char fmt[4]; - uint32_t fmt_size; - uint16_t audio_format; - uint16_t num_channels; - uint32_t sample_rate; - uint32_t byte_rate; - uint16_t block_align; - uint16_t bits_per_sample; - char data[4]; - uint32_t data_size; -} wav_header_t; + audio_sample_t spindlemotor_start; + audio_sample_t spindlemotor_loop; + audio_sample_t spindlemotor_stop; + /* Individual seek samples for each track count (indexed 0-78 for 1-79 tracks) */ + audio_sample_t seek_up[MAX_SEEK_SAMPLES]; + audio_sample_t seek_down[MAX_SEEK_SAMPLES]; + audio_sample_t post_seek_up[MAX_SEEK_SAMPLES]; + audio_sample_t post_seek_down[MAX_SEEK_SAMPLES]; + /* BIOS vendor-specific POST seek samples [vendor][track] */ + audio_sample_t bios_post_seek_up[BIOS_VENDOR_COUNT][MAX_SEEK_SAMPLES]; + audio_sample_t bios_post_seek_down[BIOS_VENDOR_COUNT][MAX_SEEK_SAMPLES]; +} drive_audio_samples_t; /* Fade duration: 75ms at 48kHz = 3600 samples */ #define FADE_DURATION_MS 75 @@ -89,6 +123,8 @@ extern const char* fdd_audio_get_profile_internal_name(int id); extern int fdd_audio_get_profile_by_internal_name(const char *internal_name); extern double fdd_audio_get_seek_time(int drive, int track_count, int is_seek_down); extern void load_profile_samples(int profile_id); +extern int fdd_get_audio_profile(int drive); +extern bios_boot_status_t fdd_get_boot_status(void); #else diff --git a/src/include/86box/hdc_ide.h b/src/include/86box/hdc_ide.h index 99d97efd98d..a1c22d04526 100644 --- a/src/include/86box/hdc_ide.h +++ b/src/include/86box/hdc_ide.h @@ -210,6 +210,7 @@ extern void ide_handlers(uint8_t board, int set); extern void ide_board_set_force_ata3(int board, int force_ata3); #ifdef EMU_ISAPNP_H extern void ide_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv); +extern void ide_pnp_config_changed_opti931(uint8_t ld, isapnp_device_config_t *config, void *priv); extern void ide_pnp_config_changed_1addr(uint8_t ld, isapnp_device_config_t *config, void *priv); #endif diff --git a/src/include/86box/hdd.h b/src/include/86box/hdd.h index e471cb54e54..dc45bb9ec73 100644 --- a/src/include/86box/hdd.h +++ b/src/include/86box/hdd.h @@ -90,6 +90,7 @@ typedef struct hdd_preset_t { const char *name; const char *internal_name; const char *model; + const char *version; uint32_t zones; uint32_t avg_spt; uint32_t heads; @@ -99,7 +100,6 @@ typedef struct hdd_preset_t { uint32_t max_multiple; double full_stroke_ms; double track_seek_ms; - const char *version_ex; } hdd_preset_t; typedef struct hdd_cache_seg_t { @@ -161,7 +161,7 @@ typedef struct hard_disk_t { void *priv; - char fn[1024]; /* Name of current image file */ + char fn[MAX_IMAGE_PATH_LEN]; /* Name of current image file */ /* Differential VHD parent file */ char vhd_parent[1280]; @@ -172,6 +172,7 @@ typedef struct hard_disk_t { uint32_t hpc; uint32_t tracks; uint32_t speed_preset; + uint32_t audio_profile; uint32_t num_zones; uint32_t phy_cyl; @@ -187,7 +188,7 @@ typedef struct hard_disk_t { const char *model; - const char *version_ex; + const char *version; hdd_zone_t zones[HDD_MAX_ZONES]; @@ -233,6 +234,7 @@ extern double hdd_seek_get_time(hard_disk_t *hdd, uint32_t dst_addr, uint8_ int hdd_preset_get_num(void); const char *hdd_preset_getname(int preset); extern const char *hdd_preset_get_internal_name(int preset); +extern uint32_t hdd_preset_get_rpm(int preset); extern int hdd_preset_get_from_internal_name(char *s); extern void hdd_preset_apply(int hdd_id); diff --git a/src/include/86box/hdd_audio.h b/src/include/86box/hdd_audio.h new file mode 100644 index 00000000000..b404efc381c --- /dev/null +++ b/src/include/86box/hdd_audio.h @@ -0,0 +1,83 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Definitions for the hard disk audio emulation. + * + * Authors: Toni Riikonen, + * + * Copyright 2026 Toni Riikonen. + */ +#ifndef EMU_HDD_AUDIO_H +#define EMU_HDD_AUDIO_H + +#include +#include <86box/hdd.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define HDD_AUDIO_PROFILE_MAX 64 + +/* Spindle motor states */ +typedef enum { + HDD_SPINDLE_STOPPED = 0, + HDD_SPINDLE_STARTING, + HDD_SPINDLE_RUNNING, + HDD_SPINDLE_STOPPING +} hdd_spindle_state_t; + +/* Audio sample configuration structure */ +typedef struct { + char filename[512]; + float volume; +} hdd_audio_sample_config_t; + +/* HDD audio profile configuration */ +typedef struct { + int id; + char name[128]; + char internal_name[64]; + uint32_t rpm; + hdd_audio_sample_config_t spindlemotor_start; + hdd_audio_sample_config_t spindlemotor_loop; + hdd_audio_sample_config_t spindlemotor_stop; + hdd_audio_sample_config_t seek_track; +} hdd_audio_profile_config_t; + +/* Functions for profile management */ +extern void hdd_audio_load_profiles(void); +extern int hdd_audio_get_profile_count(void); +extern const hdd_audio_profile_config_t *hdd_audio_get_profile(int id); +extern const char *hdd_audio_get_profile_name(int id); +extern const char *hdd_audio_get_profile_internal_name(int id); +extern uint32_t hdd_audio_get_profile_rpm(int id); +extern int hdd_audio_get_profile_by_internal_name(const char *internal_name); + +/* HDD audio initialization and cleanup */ +extern void hdd_audio_init(void); +extern void hdd_audio_reset(void); +extern void hdd_audio_close(void); +extern void hdd_audio_callback(int16_t *buffer, int length); +extern void hdd_audio_seek(hard_disk_t *hdd, uint32_t new_cylinder); + +/* Per-drive spindle control */ +extern void hdd_audio_spinup_drive(int hdd_index); +extern void hdd_audio_spindown_drive(int hdd_index); +extern hdd_spindle_state_t hdd_audio_get_drive_spindle_state(int hdd_index); + +/* Legacy functions for backward compatibility - operate on all drives */ +extern void hdd_audio_spinup(void); +extern void hdd_audio_spindown(void); +extern hdd_spindle_state_t hdd_audio_get_spindle_state(void); + +#ifdef __cplusplus +} +#endif + +#endif /* EMU_HDD_AUDIO_H */ \ No newline at end of file diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index 78714986c8d..8b32851bbf7 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -165,7 +165,9 @@ extern uint16_t scancode_map[768]; extern uint16_t scancode_config_map[768]; extern void (*keyboard_send)(uint16_t val); +extern void kbd_adddata_xt_common(uint16_t val); extern void kbd_adddata_process(uint16_t val, void (*adddata)(uint16_t val)); +extern void kbd_adddata_process_10x(uint16_t val, void (*adddata)(uint16_t val)); extern const scancode scancode_xt[512]; @@ -211,6 +213,7 @@ extern void keyboard_close(void); extern void keyboard_set_table(const scancode *ptr); extern void keyboard_poll_host(void); extern void keyboard_process(void); +extern void keyboard_process_10x(void); extern uint16_t keyboard_convert(int ch); extern void keyboard_input(int down, uint16_t scan); extern void keyboard_all_up(void); diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 941286e0fb4..92b448eebe8 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -387,8 +387,7 @@ extern void * machine_snd; /* Core functions. */ extern int machine_count(void); extern int machine_available(int m); -extern const char * machine_getname(void); -extern const char * machine_getname_ex(int m); +extern const char * machine_getname(int m); extern const char * machine_get_internal_name(void); extern const char * machine_get_nvr_name(void); extern int machine_get_machine_from_internal_name(const char *s); @@ -422,7 +421,6 @@ extern int machine_get_type(int m); extern int machine_get_chipset(int m); extern void machine_close(void); extern int machine_has_mouse(void); -extern int machine_is_sony(void); extern uint8_t machine_compaq_p1_handler(void); extern uint8_t machine_generic_p1_handler(void); @@ -736,6 +734,7 @@ extern int machine_at_dell466np_init(const machine_t *); extern int machine_at_valuepoint433_init(const machine_t *); /* VLSI 82C480 */ +extern int machine_at_monsoon_init(const machine_t *); extern int machine_at_martin_init(const machine_t *); /* m_at_socket3.c */ @@ -971,7 +970,7 @@ extern const device_t p54tp4xe_device; #endif extern int machine_at_p54tp4xe_init(const machine_t *); extern int machine_at_exp8551_init(const machine_t *); -extern int machine_at_hpholly_init(const machine_t *); +extern int machine_at_holly_init(const machine_t *); #ifdef EMU_DEVICE_H extern const device_t vectra52_device; #endif @@ -1088,6 +1087,7 @@ extern int machine_at_i430vx_init(const machine_t *); /* i430TX */ extern int machine_at_nupro592_init(const machine_t *); extern int machine_at_tx97_init(const machine_t *); +extern int machine_at_tx97xv_init(const machine_t *); extern void machine_at_optiplex_21152_init(void); extern int machine_at_optiplexgn_init(const machine_t *); extern int machine_at_tomahawk_init(const machine_t *); @@ -1204,7 +1204,9 @@ extern int machine_at_spitfire_init(const machine_t *); extern int machine_at_ma30d_init(const machine_t *); /* i440EX */ +extern int machine_at_brio83xx_init(const machine_t *); extern int machine_at_p6i440e2_init(const machine_t *); +extern int machine_at_como_init(const machine_t *); /* i440BX */ extern int machine_at_bf6_init(const machine_t *); @@ -1223,6 +1225,10 @@ extern const device_t ga686_device; #endif extern int machine_at_ga686_init(const machine_t *); #ifdef EMU_DEVICE_H +extern const device_t ms6117_device; +#endif +extern int machine_at_ms6117_init(const machine_t *); +#ifdef EMU_DEVICE_H extern const device_t ms6119_device; #endif extern int machine_at_ms6119_init(const machine_t *); diff --git a/src/include/86box/mo.h b/src/include/86box/mo.h index 5d48579eba3..53e342ed697 100644 --- a/src/include/86box/mo.h +++ b/src/include/86box/mo.h @@ -113,8 +113,8 @@ typedef struct mo_drive_t { FILE *fp; void *priv; - char image_path[1024]; - char prev_image_path[1024]; + char image_path[MAX_IMAGE_PATH_LEN]; + char prev_image_path[MAX_IMAGE_PATH_LEN + 256]; char *image_history[MO_IMAGE_HISTORY]; diff --git a/src/include/86box/network.h b/src/include/86box/network.h index 9c906ef1a1c..0642c3f53cf 100644 --- a/src/include/86box/network.h +++ b/src/include/86box/network.h @@ -50,8 +50,8 @@ #define NET_TYPE_PCAP 2 /* use the (Win)Pcap API */ #define NET_TYPE_VDE 3 /* use the VDE plug API */ #define NET_TYPE_TAP 4 /* use a linux TAP device */ -#define NET_TYPE_NMSWITCH 5 /* use the network multicast switch provider */ -#define NET_TYPE_NRSWITCH 6 /* use the network remote switch provider */ +#define NET_TYPE_NLSWITCH 5 /* use the local switch provider */ +#define NET_TYPE_NRSWITCH 6 /* use the remote switch provider */ #define NET_MAX_FRAME 1518 /* Queue size must be a power of 2 */ @@ -60,6 +60,8 @@ #define NET_QUEUE_COUNT 4 #define NET_CARD_MAX 4 #define NET_HOST_INTF_MAX 64 +#define NET_SWITCH_GRP_MIN 1 +#define NET_SWITCH_GRP_MAX 10 #define NET_PERIOD_10M 0.8 #define NET_PERIOD_100M 0.08 @@ -132,7 +134,7 @@ extern const netdrv_t net_slirp_drv; extern const netdrv_t net_vde_drv; extern const netdrv_t net_tap_drv; extern const netdrv_t net_null_drv; -extern const netdrv_t net_netswitch_drv; +extern const netdrv_t net_switch_drv; struct _netcard_t { const device_t *device; diff --git a/src/include/86box/nvr.h b/src/include/86box/nvr.h index 9485c7dcb3c..4d187b78534 100644 --- a/src/include/86box/nvr.h +++ b/src/include/86box/nvr.h @@ -95,6 +95,7 @@ extern const device_t ami_1992_nvr_device; extern const device_t ami_1994_nvr_device; extern const device_t ami_1995_nvr_device; extern const device_t via_nvr_device; +extern const device_t piix4_ami_1995_nvr_device; extern const device_t p6rp4_nvr_device; extern const device_t martin_nvr_device; extern const device_t elt_nvr_device; diff --git a/src/include/86box/plat.h b/src/include/86box/plat.h index dcf7e4d5306..efbd068989e 100644 --- a/src/include/86box/plat.h +++ b/src/include/86box/plat.h @@ -69,19 +69,10 @@ extern int strnicmp(const char *s1, const char *s2, size_t n); # define fseeko64 fseeko # define ftello64 ftello # define off64_t off_t -#elif defined(_MSC_VER) -// # define fopen64 fopen -# define fseeko64 _fseeki64 -# define ftello64 _ftelli64 -# define off64_t off_t #endif -#ifdef _MSC_VER -# define UNUSED(arg) arg -#else /* A hack (GCC-specific?) to allow us to ignore unused parameters. */ # define UNUSED(arg) __attribute__((unused)) arg -#endif /* Return the size (in wchar's) of a wchar_t array. */ #define sizeof_w(x) (sizeof((x)) / sizeof(wchar_t)) @@ -90,28 +81,23 @@ extern int strnicmp(const char *s1, const char *s2, size_t n); # include # define atomic_flag_t std::atomic_flag # define atomic_bool_t std::atomic_bool + extern "C" { #else # include # define atomic_flag_t atomic_flag # define atomic_bool_t atomic_bool -#endif -#if defined(_MSC_VER) -# define ssize_t intptr_t -#endif -#ifdef _MSC_VER -# define fallthrough do {} while (0) /* fallthrough */ +#if __has_attribute(fallthrough) +# define fallthrough __attribute__((fallthrough)) #else -# if __has_attribute(fallthrough) -# define fallthrough __attribute__((fallthrough)) -# else -# if __has_attribute(__fallthrough__) -# define fallthrough __attribute__((__fallthrough__)) -# endif -# define fallthrough do {} while (0) /* fallthrough */ +# if __has_attribute(__fallthrough__) +# define fallthrough __attribute__((__fallthrough__)) # endif +# define fallthrough do {} while (0) /* fallthrough */ +#endif + #endif /* Global variables residing in the platform module. */ @@ -165,8 +151,12 @@ extern void plat_resize_request(int x, int y, int monitor_index); extern int plat_language_code(char *langcode); extern void plat_language_code_r(int id, char *outbuf, int len); extern void plat_get_cpu_string(char *outbuf, uint8_t len); +#ifdef _WIN32 +extern void plat_get_system_directory(char *outbuf); +#endif extern void plat_set_thread_name(void *thread, const char *name); extern void plat_break(void); +extern void plat_send_to_clipboard(unsigned char *rgb, int width, int height); /* Resource management. */ extern wchar_t *plat_get_string(int id); diff --git a/src/include/86box/plat_fallthrough.h b/src/include/86box/plat_fallthrough.h index 2ba0008483b..1221f03fa80 100644 --- a/src/include/86box/plat_fallthrough.h +++ b/src/include/86box/plat_fallthrough.h @@ -16,18 +16,16 @@ #define EMU_PLAT_FALLTHROUGH_H #ifndef EMU_PLAT_H -#ifdef _MSC_VER -# define fallthrough do {} while (0) /* fallthrough */ + +#if __has_attribute(fallthrough) +# define fallthrough __attribute__((fallthrough)) #else -# if __has_attribute(fallthrough) -# define fallthrough __attribute__((fallthrough)) -# else -# if __has_attribute(__fallthrough__) -# define fallthrough __attribute__((__fallthrough__)) -# endif -# define fallthrough do {} while (0) /* fallthrough */ +# if __has_attribute(__fallthrough__) +# define fallthrough __attribute__((__fallthrough__)) # endif +# define fallthrough do {} while (0) /* fallthrough */ #endif + #endif #endif /*EMU_PLAT_FALLTHROUGH_H*/ diff --git a/src/include/86box/plat_unused.h b/src/include/86box/plat_unused.h index 4688a615b1f..4090f3358b9 100644 --- a/src/include/86box/plat_unused.h +++ b/src/include/86box/plat_unused.h @@ -19,12 +19,9 @@ #define EMU_PLAT_UNUSED_H #ifndef EMU_PLAT_H -#ifdef _MSC_VER -# define UNUSED(arg) arg -#else /* A hack (GCC-specific?) to allow us to ignore unused parameters. */ + # define UNUSED(arg) __attribute__((unused)) arg -#endif -#endif +#endif #endif /*EMU_PLAT_UNUSED_H*/ diff --git a/src/include/86box/rdisk.h b/src/include/86box/rdisk.h index 6f0255847d1..fff53ec6300 100644 --- a/src/include/86box/rdisk.h +++ b/src/include/86box/rdisk.h @@ -91,8 +91,8 @@ typedef struct rdisk_drive_t { FILE *fp; void *priv; - char image_path[1024]; - char prev_image_path[1024]; + char image_path[MAX_IMAGE_PATH_LEN]; + char prev_image_path[MAX_IMAGE_PATH_LEN + 256]; char *image_history[RDISK_IMAGE_HISTORY]; diff --git a/src/include/86box/snd_ac97.h b/src/include/86box/snd_ac97.h index 0bad4efa032..a0b5a8d727a 100644 --- a/src/include/86box/snd_ac97.h +++ b/src/include/86box/snd_ac97.h @@ -108,6 +108,7 @@ #define AC97_CODEC_ALC100 AC97_VENDOR_ID('A', 'L', 'C', 0x20) #define AC97_CODEC_CS4297 AC97_VENDOR_ID('C', 'R', 'Y', 0x03) #define AC97_CODEC_CS4297A AC97_VENDOR_ID('C', 'R', 'Y', 0x11) +#define AC97_CODEC_ICE1232 AC97_VENDOR_ID('I', 'C', 'E', 0x11) #define AC97_CODEC_STAC9708 AC97_VENDOR_ID(0x83, 0x84, 0x76, 0x08) #define AC97_CODEC_STAC9721 AC97_VENDOR_ID(0x83, 0x84, 0x76, 0x09) #define AC97_CODEC_TR28023 AC97_VENDOR_ID('T', 'R', 'A', 0x03) @@ -161,9 +162,11 @@ extern const device_t alc100_device; extern const device_t cs4297_device; extern const device_t cs4297a_device; # define ct1297_device tr28023_device +extern const device_t ice1232_device; extern const device_t stac9708_device; extern const device_t stac9721_device; extern const device_t tr28023_device; +# define vt1611a_device ice1232_device extern const device_t w83971d_device; extern const device_t wm9701a_device; #ifdef USE_SOFTMODEM diff --git a/src/include/86box/snd_azt2316a.h b/src/include/86box/snd_azt2316a.h index 8aae3f1ff32..266193e55cf 100644 --- a/src/include/86box/snd_azt2316a.h +++ b/src/include/86box/snd_azt2316a.h @@ -2,5 +2,7 @@ #define SOUND_AZT2316A_H extern void azt2316a_enable_wss(uint8_t enable, void *priv); +extern void aztpr16_update_mixer(void *priv); +extern void aztpr16_wss_mode(uint8_t mode, void *priv); #endif /*SOUND_AZT2316A*/ diff --git a/src/include/86box/snd_sb_dsp.h b/src/include/86box/snd_sb_dsp.h index 0bc719d98fe..200912c4209 100644 --- a/src/include/86box/snd_sb_dsp.h +++ b/src/include/86box/snd_sb_dsp.h @@ -8,16 +8,17 @@ #define SB_SUBTYPE_CLONE_AZT2316A_0X11 1 /* Aztech Sound Galaxy Pro 16 AB, DSP 3.1 - SBPRO2 clone */ #define SB_SUBTYPE_CLONE_AZT1605_0X0C 2 /* Aztech Sound Galaxy Nova 16 Extra / Packard Bell Forte 16, DSP 2.1 - SBPRO2 clone */ -#define SB_SUBTYPE_ESS_ES688 3 /* ESS Technology ES688 */ -#define SB_SUBTYPE_ESS_ES1688 4 /* ESS Technology ES1688 */ +#define SB_SUBTYPE_CLONE_AZTPR16_0X09 3 /* Aztech Sound Galaxy Pro 16 Extra */ +#define SB_SUBTYPE_ESS_ES688 4 /* ESS Technology ES688 */ +#define SB_SUBTYPE_ESS_ES1688 5 /* ESS Technology ES1688 */ /* ESS-related */ #define IS_ESS(dsp) ((dsp)->sb_subtype >= SB_SUBTYPE_ESS_ES688) /* Check for future ESS cards here */ #define IS_NOT_ESS(dsp) ((dsp)->sb_subtype < SB_SUBTYPE_ESS_ES688) /* Check for future ESS cards here */ /* aztech-related */ -#define IS_AZTECH(dsp) ((dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZT2316A_0X11 || (dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C) /* check for future AZT cards here */ -#define AZTECH_EEPROM_SIZE 16 +#define IS_AZTECH(dsp) ((dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZT2316A_0X11 || (dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C || (dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZTPR16_0X09) /* check for future AZT cards here */ +#define AZTECH_EEPROM_SIZE 36 typedef struct sb_dsp_t { int sb_type; diff --git a/src/include/86box/sound.h b/src/include/86box/sound.h index 4ce2d99f0ea..71cd65e5ad0 100644 --- a/src/include/86box/sound.h +++ b/src/include/86box/sound.h @@ -103,6 +103,9 @@ extern void sound_cd_thread_reset(void); extern void sound_fdd_thread_init(void); extern void sound_fdd_thread_end(void); +extern void sound_hdd_thread_init(void); +extern void sound_hdd_thread_end(void); + extern void closeal(void); extern void inital(void); extern void givealbuffer(const void *buf); @@ -110,6 +113,7 @@ extern void givealbuffer_music(const void *buf); extern void givealbuffer_wt(const void *buf); extern void givealbuffer_cd(const void *buf); extern void givealbuffer_fdd(const void *buf, const uint32_t size); +extern void givealbuffer_hdd(const void *buf, const uint32_t size); #define sb_vibra16c_onboard_relocate_base sb_vibra16s_onboard_relocate_base #define sb_vibra16cl_onboard_relocate_base sb_vibra16s_onboard_relocate_base @@ -122,11 +126,13 @@ extern const device_t adlib_device; extern const device_t adlib_mca_device; extern const device_t adgold_device; +/* Analog Devices AD1816 */ +extern const device_t ad1816_device; + /* Aztech Sound Galaxy 16 */ extern const device_t azt2316a_device; -extern const device_t acermagic_s20_device; -extern const device_t mirosound_pcm10_device; extern const device_t azt1605_device; +extern const device_t aztpr16_device; /* C-Media CMI8x38 */ extern const device_t cmi8338_device; @@ -223,6 +229,8 @@ extern const device_t entertainer_device; extern const device_t mmb_device; /* OPTi 82c93x */ +extern const device_t acermagic_s20_device; +extern const device_t mirosound_pcm10_device; extern const device_t opti_82c930_device; extern const device_t opti_82c931_device; diff --git a/src/include/86box/sound_util.h b/src/include/86box/sound_util.h new file mode 100644 index 00000000000..95e95a3607a --- /dev/null +++ b/src/include/86box/sound_util.h @@ -0,0 +1,28 @@ +#ifndef SOUND_UTIL_H +#define SOUND_UTIL_H + +#include + +/* WAV file header structure */ +typedef struct wav_header_t { + char riff[4]; + uint32_t file_size; + char wave[4]; + char fmt[4]; + uint32_t fmt_size; + uint16_t audio_format; + uint16_t num_channels; + uint32_t sample_rate; + uint32_t byte_rate; + uint16_t block_align; + uint16_t bits_per_sample; + char data[4]; + uint32_t data_size; +} wav_header_t; + +/* Load a WAV file and return stereo 16-bit samples + * Returns allocated buffer (caller must free) or NULL on error + * sample_count receives the number of stereo sample pairs */ +int16_t *sound_load_wav(const char *filename, int *sample_count); + +#endif /* SOUND_UTIL_H */ \ No newline at end of file diff --git a/src/include/86box/timer.h b/src/include/86box/timer.h index 37a03d9caaa..38784e154f7 100644 --- a/src/include/86box/timer.h +++ b/src/include/86box/timer.h @@ -1,6 +1,14 @@ #ifndef _TIMER_H_ #define _TIMER_H_ +#ifndef int128_t +#define int128_t __int128 +#endif + +#ifndef uint128_t +#define uint128_t unsigned __int128 +#endif + extern uint64_t tsc; /* Maximum period, currently 1 second. */ @@ -11,18 +19,6 @@ extern uint64_t tsc; #define TIMER_SPLIT 2 #define TIMER_ENABLED 1 -#pragma pack(push, 1) -typedef struct ts_struct_t { - uint32_t frac; - uint32_t integer; -} ts_struct_t; -#pragma pack(pop) - -typedef union ts_t { - uint64_t ts64; - ts_struct_t ts32; -} ts_t; - /*Timers are based on the CPU Time Stamp Counter. Timer timestamps are in a 32:32 fixed point format, with the integer part compared against the TSC. The fractional part is used when advancing the timestamp to ensure a more accurate @@ -36,12 +32,8 @@ typedef union ts_t { to repeat, the callback must call timer_advance_u64(). This is a change from the old timer API.*/ typedef struct pc_timer_t { -#ifdef USE_PCEM_TIMER - uint32_t ts_integer; + uint64_t ts_integer; uint32_t ts_frac; -#else - ts_t ts; -#endif int flags; /* The flags are defined above. */ int in_callback; double period; /* This is used for large period timers to count @@ -60,7 +52,7 @@ extern "C" { /*Timestamp of nearest enabled timer. CPU emulation must call timer_process() when TSC matches or exceeds this.*/ -extern uint32_t timer_target; +extern uint64_t timer_target; /*Enable timer, without updating timestamp*/ extern void timer_enable(pc_timer_t *timer); @@ -82,18 +74,31 @@ extern void timer_add(pc_timer_t *timer, void (*callback)(void *priv), void *pri extern uint64_t TIMER_USEC; /*True if timer a expires before timer b*/ -#define TIMER_LESS_THAN(a, b) ((int64_t) ((a)->ts.ts64 - (b)->ts.ts64) <= 0) +#define TIMER_LESS_THAN(a, b) ((int64_t) ((a)->ts_integer - (b)->ts_integer) <= 0) /*True if timer a expires before 32 bit integer timestamp b*/ -#define TIMER_LESS_THAN_VAL(a, b) ((int32_t) ((a)->ts.ts32.integer - (b)) <= 0) +#define TIMER_LESS_THAN_VAL(a, b) ((int64_t) ((a)->ts_integer - (b)) <= 0) /*True if 32 bit integer timestamp a expires before 32 bit integer timestamp b*/ -#define TIMER_VAL_LESS_THAN_VAL(a, b) ((int32_t) ((a) - (b)) <= 0) +#define TIMER_VAL_LESS_THAN_VAL(a, b) ((int64_t) ((a) - (b)) <= 0) + +#ifndef printf +#include +#endif /*Advance timer by delay, specified in 32:32 format. This should be used to resume a recurring timer in a callback routine*/ static __inline void timer_advance_u64(pc_timer_t *timer, uint64_t delay) { - timer->ts.ts64 += delay; + uint64_t int_delay = delay >> 32; + uint32_t frac_delay = delay & 0xffffffff; + + if (int_delay & 0x0000000080000000ULL) + int_delay |= 0xffffffff00000000ULL; + + if ((frac_delay + timer->ts_frac) < frac_delay) + timer->ts_integer++; + timer->ts_frac += frac_delay; + timer->ts_integer += int_delay; timer_enable(timer); } @@ -103,9 +108,14 @@ timer_advance_u64(pc_timer_t *timer, uint64_t delay) static __inline void timer_set_delay_u64(pc_timer_t *timer, uint64_t delay) { - timer->ts.ts64 = 0ULL; - timer->ts.ts32.integer = tsc; - timer->ts.ts64 += delay; + uint64_t int_delay = delay >> 32; + uint32_t frac_delay = delay & 0xffffffff; + + if (int_delay & 0x0000000080000000ULL) + int_delay |= 0xffffffff00000000ULL; + + timer->ts_frac = frac_delay; + timer->ts_integer = int_delay + (uint64_t)tsc; timer_enable(timer); } @@ -125,21 +135,19 @@ timer_is_on(pc_timer_t *timer) } /*Return integer timestamp of timer*/ -static __inline uint32_t +static __inline uint64_t timer_get_ts_int(pc_timer_t *timer) { - return timer->ts.ts32.integer; + return timer->ts_integer; } /*Return remaining time before timer expires, in us. If the timer has already expired then return 0*/ -static __inline uint32_t +static __inline uint64_t timer_get_remaining_us(pc_timer_t *timer) { - int64_t remaining; - if (timer->flags & TIMER_ENABLED) { - remaining = (int64_t) (timer->ts.ts64 - (uint64_t) (tsc << 32)); + int128_t remaining = (((uint128_t)timer->ts_integer << 32) | timer->ts_frac) - ((uint128_t)tsc << 32); if (remaining < 0) return 0; @@ -151,13 +159,11 @@ timer_get_remaining_us(pc_timer_t *timer) /*Return remaining time before timer expires, in 32:32 timestamp format. If the timer has already expired then return 0*/ -static __inline uint64_t +static __inline uint128_t timer_get_remaining_u64(pc_timer_t *timer) { - int64_t remaining; - if (timer->flags & TIMER_ENABLED) { - remaining = (int64_t) (timer->ts.ts64 - (uint64_t) (tsc << 32)); + int128_t remaining = (((uint128_t)timer->ts_integer << 32) | timer->ts_frac) - ((uint128_t)tsc << 32); if (remaining < 0) return 0; diff --git a/src/include/86box/ui.h b/src/include/86box/ui.h index 9bfae43304b..08719cc2b0b 100644 --- a/src/include/86box/ui.h +++ b/src/include/86box/ui.h @@ -71,6 +71,8 @@ extern void ui_sb_set_text(char *str); extern void ui_sb_bugui(char *str); extern void ui_sb_mt32lcd(char *str); +extern void ui_update_force_interpreter(void); + #ifdef __cplusplus } #endif diff --git a/src/include/86box/version.h.in b/src/include/86box/version.h.in index 096bb651618..693bb80951d 100644 --- a/src/include/86box/version.h.in +++ b/src/include/86box/version.h.in @@ -50,7 +50,7 @@ /* Web URL info. */ #define EMU_SITE "86box.net" #define EMU_SITE_W LSTR(EMU_SITE) -#define EMU_ROMS_URL "https://github.com/86Box/roms/releases/latest" +#define EMU_ROMS_URL "https://github.com/@CMAKE_PROJECT_NAME@/roms/releases/latest" #define EMU_ROMS_URL_W LSTR(EMU_ROMS_URL) #ifdef RELEASE_BUILD # define EMU_DOCS_URL "https://86box.readthedocs.io/en/v@CMAKE_PROJECT_VERSION_MAJOR@.@CMAKE_PROJECT_VERSION_MINOR@/" diff --git a/src/include/86box/vid_mda.h b/src/include/86box/vid_mda.h index 17c02834327..4d11305f4e9 100644 --- a/src/include/86box/vid_mda.h +++ b/src/include/86box/vid_mda.h @@ -18,6 +18,7 @@ // Defines #define MDA_CRTC_NUM_REGISTERS 32 +#define MDA_VRAM 0x1000 // Enums & structures diff --git a/src/include/86box/vid_voodoo_codegen_x86-64.h b/src/include/86box/vid_voodoo_codegen_x86-64.h index e8b7299f24a..0e43c15bdc2 100644 --- a/src/include/86box/vid_voodoo_codegen_x86-64.h +++ b/src/include/86box/vid_voodoo_codegen_x86-64.h @@ -8,11 +8,7 @@ #ifndef VIDEO_VOODOO_CODEGEN_X86_64_H #define VIDEO_VOODOO_CODEGEN_X86_64_H -#ifdef _MSC_VER -# include -#else -# include -#endif +#include #define BLOCK_NUM 8 #define BLOCK_MASK (BLOCK_NUM - 1) @@ -653,13 +649,15 @@ codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *pa static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int depthop) { - int block_pos = 0; - int z_skip_pos = 0; - int a_skip_pos = 0; - int chroma_skip_pos = 0; - int depth_jump_pos = 0; - int depth_jump_pos2 = 0; - int loop_jump_pos = 0; + int block_pos = 0; + int z_skip_pos = 0; + int a_skip_pos = 0; + int amask_skip_pos = 0; + int stipple_skip_pos = 0; + int chroma_skip_pos = 0; + int depth_jump_pos = 0; + int depth_jump_pos2 = 0; + int loop_jump_pos = 0; #if 0 xmm_01_w = (__m128i)0x0001000100010001ull; xmm_ff_w = (__m128i)0x00ff00ff00ff00ffull; @@ -765,6 +763,69 @@ voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, addquad((uint64_t) (uintptr_t) &i_00_ff_w); loop_jump_pos = block_pos; + if (params->fbzMode & FBZ_STIPPLE) { + /* Stipple enabled. */ + if (params->fbzMode & FBZ_STIPPLE_PATT) { + /* x64's BT instruction is too slow. So use TEST instead. */ + addbyte(0x4c); /* MOV RBX, R14(real_y)*/ + addbyte(0x89); + addbyte(0xf3); + + addbyte(0x83); /* AND EBX, 3 */ + addbyte(0xe3); + addbyte(0x03); + + addbyte(0xc1); /* SHL EBX, 3 */ + addbyte(0xe3); + addbyte(0x03); + + addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + + addbyte(0xf7); /* NOT EAX */ + addbyte(0xd0); + + addbyte(0x83); /* AND EAX, 7 */ + addbyte(0xe0); + addbyte(0x07); + + addbyte(0x09); /* OR EAX, EBX */ + addbyte(0xc3); + + addbyte(0x88); /* MOV CL, AL */ + addbyte(0xc1); + + addbyte(0xb8); /* MOV EAX, 1*/ + addlong(1); + + addbyte(0xd3); /* SHL EAX, CL */ + addbyte(0xe0); + + addbyte(0x85); /* TEST state->stipple[EDI], EAX */ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, stipple)); + + addbyte(0x0f); /* JZ stipple_skip_pos */ + addbyte(0x84); + stipple_skip_pos = block_pos; + addlong(0); + } else { + addbyte(0xd1); /* ROR state->stipple[EDI], 1*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, stipple)); + + addbyte(0xf7); /* TEST state->stipple[EDI], 0x80000000 */ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, stipple)); + addlong(0x80000000); + + addbyte(0x0f); /* JZ stipple_skip_pos */ + addbyte(0x84); + stipple_skip_pos = block_pos; + addlong(0); + } + } addbyte(0x4c); /*MOV RSI, R15*/ addbyte(0x89); addbyte(0xfe); @@ -1732,6 +1793,15 @@ voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, addbyte(0xdb); break; } + if (params->fbzMode & FBZ_ALPHA_MASK) { + addbyte(0xf7); /*TEST EBX, 1*/ + addbyte(0xc3); + addlong(1); + addbyte(0x0f); /* JZ amask_skip_pos */ + addbyte(0x84); + amask_skip_pos = block_pos; + addlong(0); + } /*ECX = a_local*/ switch (cca_localselect) { case CCA_LOCALSELECT_ITER_A: @@ -2397,6 +2467,27 @@ voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, } if (params->alphaMode & (1 << 4)) { + if (params->fbzMode & FBZ_ALPHA_ENABLE) { + addbyte(0x8b); /*MOV EBX, state->x[EDI]*/ + addbyte(0x9f); + if (params->aux_tiled) + addlong(offsetof(voodoo_state_t, x_tiled)); + else + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x48); /*MOV RCX, aux_mem[RDI]*/ + addbyte(0x8b); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, aux_mem)); + addbyte(0x0f); /*MOVZX EBX, [ECX+EBX*2]*/ + addbyte(0xb7); + addbyte(0x1c); + addbyte(0x59); + } else { + addbyte(0x48); /*MOV RBX, 0xff*/ + addbyte(0xc7); + addbyte(0xc3); + addlong(0xff); + } addbyte(0x49); /*MOV R8, rgb565*/ addbyte(0xb8); addquad((uintptr_t) rgb565); @@ -2412,6 +2503,8 @@ voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, addlong(offsetof(voodoo_state_t, fb_mem)); addbyte(0x01); /*ADD EDX, EDX*/ addbyte(0xd2); + addbyte(0x01); /*ADD EBX, EBX*/ + addbyte(0xdb); addbyte(0x0f); /*MOVZX EAX, [RBP+RAX*2]*/ addbyte(0xb7); addbyte(0x44); @@ -2506,6 +2599,36 @@ voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, addbyte(8); break; case AFUNC_ADST_ALPHA: + addbyte(0x66); /*PMULLW XMM4, R10(alookup)[EBX*8]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x24); + addbyte(0xda); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, R10(alookup)[1*8]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x62); + addbyte(8 * 2); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); break; case AFUNC_AONE: break; @@ -2581,10 +2704,36 @@ voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, addbyte(8); break; case AFUNC_AOMDST_ALPHA: - addbyte(0x66); /*PXOR XMM4, XMM4*/ + addbyte(0x66); /*PMULLW XMM4, R11(aminuslookup)[EBX*8]*/ + addbyte(0x41); addbyte(0x0f); - addbyte(0xef); - addbyte(0xe4); + addbyte(0xd5); + addbyte(0x24); + addbyte(0xdb); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, R10(alookup)[1*8]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x62); + addbyte(8 * 2); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); break; case AFUNC_ACOLORBEFOREFOG: addbyte(0x66); /*PMULLW XMM4, XMM15(colbfog)*/ @@ -2689,6 +2838,36 @@ voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, addbyte(8); break; case AFUNC_ADST_ALPHA: + addbyte(0x66); /*PMULLW XMM0, R10(alookup)[EBX*8]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x04); + addbyte(0xda); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, R10(alookup)[1*8]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x42); + addbyte(8 * 2); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); break; case AFUNC_AONE: break; @@ -2764,22 +2943,62 @@ voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, addbyte(8); break; case AFUNC_AOMDST_ALPHA: - addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x66); /*PMULLW XMM0, R11(aminuslookup)[EBX*8]*/ + addbyte(0x41); addbyte(0x0f); - addbyte(0xef); - addbyte(0xc0); + addbyte(0xd5); + addbyte(0x04); + addbyte(0xdb); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x42); + addbyte(8 * 2); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); break; case AFUNC_ASATURATE: - addbyte(0x66); /*PMULLW XMM0, XMM11(minus_254)*/ + addbyte(0x89); /* MOV EAX, EBX */ + addbyte(0xd8); + addbyte(0xd1); /* SHR EAX, 1 */ + addbyte(0xe8); + addbyte(0x34); /* XOR AL, 0xFF */ + addbyte(0xFF); + addbyte(0xd1); /* SHL EAX, 1 */ + addbyte(0xe0); + addbyte(0x39); /* CMP EDX, EAX */ + addbyte(0xc2); + addbyte(0x0f); /* CMOVB EAX, EDX */ + addbyte(0x42); + addbyte(0xc2); + addbyte(0x66); /*PMULLW XMM0, R10(alookup)[EAX*8]*/ addbyte(0x41); addbyte(0x0f); addbyte(0xd5); - addbyte(0xc3); + addbyte(0x04); + addbyte(0xc2); addbyte(0xf3); /*MOVQ XMM5, XMM0*/ addbyte(0x0f); addbyte(0x7e); addbyte(0xe8); - addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x66); /*PADDW XMM0, R10(alookup)[1*8]*/ addbyte(0x41); addbyte(0x0f); addbyte(0xfd); @@ -2811,6 +3030,48 @@ voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, addbyte(0x0f); addbyte(0x67); addbyte(0xc0); + + addbyte(0x31); /*XOR EAX, EAX */ + addbyte(0xc0); + + if (dest_aafunc == 4) { + addbyte(0xc1); /*SHL EBX, 0x7*/ + addbyte(0xe3); + addbyte(0x07); + addbyte(0x01); /*ADD EAX, EBX*/ + addbyte(0xd8); + } + + if (src_aafunc == 4) { + addbyte(0xc1); /*SHL EDX, 0x7*/ + addbyte(0xe2); + addbyte(0x07); + addbyte(0x01); /*ADD EAX, EDX*/ + addbyte(0xd0); + } + + addbyte(0xc1); /* SHR EAX, 8 */ + addbyte(0xc8); + addbyte(0x08); + addbyte(0x89); /* MOV EDX, EAX */ + addbyte(0xC2); + } + + if ((params->fbzMode & (FBZ_DEPTH_WMASK | FBZ_ALPHA_ENABLE)) == (FBZ_DEPTH_WMASK | FBZ_ALPHA_ENABLE)) { + addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ + addbyte(0x87); + if (params->aux_tiled) + addlong(offsetof(voodoo_state_t, x_tiled)); + else + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x48); /*MOV RSI, aux_mem*/ + addbyte(0x8b); + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, aux_mem)); + addbyte(0x66); /*MOV [ESI+EAX*2], DX*/ + addbyte(0x89); + addbyte(0x14); + addbyte(0x46); } addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ @@ -2959,7 +3220,8 @@ voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, addbyte(0x56); } - if ((params->fbzMode & (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) == (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) { + + if ((params->fbzMode & (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) == (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE) && !(params->fbzMode & FBZ_ALPHA_ENABLE)) { addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ addbyte(0x97); if (params->aux_tiled) @@ -2986,6 +3248,10 @@ voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, *(uint32_t *) &code_block[a_skip_pos] = (block_pos - a_skip_pos) - 4; if (chroma_skip_pos) *(uint32_t *) &code_block[chroma_skip_pos] = (block_pos - chroma_skip_pos) - 4; + if (amask_skip_pos) + *(uint32_t *) &code_block[amask_skip_pos] = (block_pos - amask_skip_pos) - 4; + if (stipple_skip_pos) + *(uint32_t *) &code_block[stipple_skip_pos] = (block_pos - stipple_skip_pos) - 4; addbyte(0x4c); /*MOV RSI, R15*/ addbyte(0x89); diff --git a/src/include/86box/vid_voodoo_codegen_x86.h b/src/include/86box/vid_voodoo_codegen_x86.h index 996bd28f1ab..f479a5413e0 100644 --- a/src/include/86box/vid_voodoo_codegen_x86.h +++ b/src/include/86box/vid_voodoo_codegen_x86.h @@ -8,11 +8,7 @@ #ifndef VIDEO_VOODOO_CODEGEN_X86_H #define VIDEO_VOODOO_CODEGEN_X86_H -#ifdef _MSC_VER -# include -#else -# include -#endif +#include #define BLOCK_NUM 8 #define BLOCK_MASK (BLOCK_NUM - 1) diff --git a/src/include/86box/vid_voodoo_common.h b/src/include/86box/vid_voodoo_common.h index d87c1f73192..a6174e1cd41 100644 --- a/src/include/86box/vid_voodoo_common.h +++ b/src/include/86box/vid_voodoo_common.h @@ -74,6 +74,13 @@ typedef union rgba_u { #define FIFO_FULL ((voodoo->fifo_write_idx - voodoo->fifo_read_idx) >= FIFO_SIZE - 4) #define FIFO_EMPTY (voodoo->fifo_read_idx == voodoo->fifo_write_idx) +#define VOODOO_BUF_FRONT 0 +#define VOODOO_BUF_BACK 1 +#define VOODOO_BUF_AUX 2 +#define VOODOO_BUF_UNKNOWN 3 +#define VOODOO_BUF_COUNT 4 +#define VOODOO_BUF_NONE 0xff + #define FIFO_TYPE 0xff000000 #define FIFO_ADDR 0x00ffffff @@ -98,6 +105,8 @@ typedef struct { uint32_t addr_type; uint32_t val; + uint8_t target_buf; + uint8_t pad[3]; } fifo_entry_t; typedef struct voodoo_params_t { @@ -356,6 +365,8 @@ typedef struct voodoo_t { event_t *wake_fifo_thread; event_t *wake_main_thread; event_t *fifo_not_full_event; + event_t *fifo_empty_event; + ATOMIC_INT fifo_empty_signaled; event_t *render_not_full_event[4]; event_t *wake_render_thread[4]; @@ -399,6 +410,8 @@ typedef struct voodoo_t { ATOMIC_INT cmd_written; ATOMIC_INT cmd_written_fifo; ATOMIC_INT cmd_written_fifo_2; + ATOMIC_INT pending_fb_writes_buf[VOODOO_BUF_COUNT]; + ATOMIC_INT pending_draw_cmds_buf[VOODOO_BUF_COUNT]; voodoo_params_t params_buffer[PARAM_SIZE]; ATOMIC_INT params_read_idx[4]; @@ -627,6 +640,12 @@ typedef struct voodoo_t { int fb_write_buffer; int fb_draw_buffer; int buffer_cutoff; + int queued_disp_buffer; + int queued_draw_buffer; + int queued_fb_write_buffer; + int queued_fb_draw_buffer; + uint32_t queued_lfbMode; + uint32_t queued_fbzMode; uint32_t tile_base; uint32_t tile_stride; @@ -657,6 +676,32 @@ typedef struct voodoo_t { uint64_t time; int render_time[4]; + uint64_t fifo_full_waits; + uint64_t fifo_full_wait_ticks; + uint64_t fifo_full_spin_checks; + uint64_t fifo_empty_waits; + uint64_t fifo_empty_wait_ticks; + uint64_t fifo_empty_spin_checks; + uint64_t render_waits; + uint64_t render_wait_ticks; + uint64_t render_wait_spin_checks; + uint64_t readl_fb_count; + uint64_t readl_fb_sync_count; + uint64_t readl_fb_nosync_count; + uint64_t readl_fb_relaxed_count; + uint64_t readl_fb_sync_buf[3]; + uint64_t readl_fb_nosync_buf[3]; + uint64_t readl_fb_relaxed_buf[3]; + uint64_t readl_reg_count; + uint64_t readl_tex_count; + int wait_stats_enabled; + int wait_stats_explicit; + int lfb_relax_enabled; + int lfb_relax_full; + int lfb_relax_ignore_cmdfifo; + int lfb_relax_ignore_draw; + int lfb_relax_ignore_fb_writes; + int lfb_relax_front_sync; int force_blit_count; int can_blit; @@ -667,6 +712,8 @@ typedef struct voodoo_t { struct voodoo_set_t *set; + uint32_t launch_pending; + uint8_t fifo_thread_run; uint8_t render_thread_run[4]; diff --git a/src/include/86box/vid_voodoo_regs.h b/src/include/86box/vid_voodoo_regs.h index 6aeb98bccfc..9f3260c9fb2 100644 --- a/src/include/86box/vid_voodoo_regs.h +++ b/src/include/86box/vid_voodoo_regs.h @@ -358,6 +358,7 @@ enum { enum { FBZ_CHROMAKEY = (1 << 1), + FBZ_STIPPLE = (1 << 2), FBZ_W_BUFFER = (1 << 3), FBZ_DEPTH_ENABLE = (1 << 4), @@ -366,11 +367,16 @@ enum { FBZ_DEPTH_WMASK = (1 << 10), FBZ_DITHER_2x2 = (1 << 11), + FBZ_STIPPLE_PATT = (1 << 12), + + FBZ_ALPHA_MASK = (1 << 13), + FBZ_DRAW_FRONT = 0x0000, FBZ_DRAW_BACK = 0x4000, FBZ_DRAW_MASK = 0xc000, FBZ_DEPTH_BIAS = (1 << 16), + FBZ_ALPHA_ENABLE = (1 << 18), FBZ_DITHER_SUB = (1 << 19), FBZ_DEPTH_SOURCE = (1 << 20), @@ -655,6 +661,8 @@ enum { #define src_afunc ((params->alphaMode >> 8) & 0xf) #define dest_afunc ((params->alphaMode >> 12) & 0xf) +#define src_aafunc ((params->alphaMode >> 16) & 0xf) +#define dest_aafunc ((params->alphaMode >> 20) & 0xf) #define alpha_func ((params->alphaMode >> 1) & 7) #define a_ref (params->alphaMode >> 24) #define depth_op ((params->fbzMode >> 5) & 7) diff --git a/src/include/86box/video.h b/src/include/86box/video.h index acaf7cdc4f4..b7f86ac1832 100644 --- a/src/include/86box/video.h +++ b/src/include/86box/video.h @@ -58,6 +58,21 @@ enum { VIDEO_AGP }; +typedef enum video_font_format_e +{ + FONT_FORMAT_MDA = 0, + FONT_FORMAT_PC200 = 1, + FONT_FORMAT_CGA = 2, + FONT_FORMAT_WY700 = 3, + FONT_FORMAT_MDSI_GENIUS = 4, + FONT_FORMAT_TOSHIBA_3100E = 5, + FONT_FORMAT_KSC6501 = 6, + FONT_FORMAT_SIGMA = 7, + FONT_FORMAT_PC1512_T1000 = 8, + FONT_FORMAT_IM1024 = 9, + FONT_FORMAT_PRAVETZ = 10, +} video_font_format; + #define VIDEO_FLAG_TYPE_CGA 0 #define VIDEO_FLAG_TYPE_MDA 1 #define VIDEO_FLAG_TYPE_SPECIAL 2 @@ -130,6 +145,9 @@ typedef struct monitor_t { int mon_renderedframes; atomic_int mon_actualrenderedframes; atomic_int mon_screenshots; + atomic_int mon_screenshots_clipboard; + atomic_int mon_screenshots_raw; + atomic_int mon_screenshots_raw_clipboard; uint32_t *mon_pal_lookup; int *mon_cga_palette; int mon_pal_lookup_static; /* Whether it should not be freed by the API. */ @@ -202,8 +220,6 @@ extern int video_fullscreen; extern int video_fullscreen_scale; extern uint8_t fontdat[2048][8]; /* IBM CGA font */ extern uint8_t fontdatm[2048][16]; /* IBM MDA font */ -extern uint8_t fontdat2[2048][8]; /* IBM CGA 2nd instance font */ -extern uint8_t fontdatm2[2048][16]; /* IBM MDA 2nd instance font */ extern uint8_t fontdatw[512][32]; /* Wyse700 font */ extern uint8_t fontdat8x12[256][16]; /* MDSI Genius font */ extern uint8_t fontdat12x18[256][36]; /* IM1024 font */ @@ -253,9 +269,6 @@ extern int video_get_video_from_internal_name(char *s); extern int video_card_get_flags(int card); extern int video_is_mda(void); extern int video_is_cga(void); -extern int video_is_ega_vga(void); -extern int video_is_8514(void); -extern int video_is_xga(void); extern void video_inform_monitor(int type, const video_timings_t *ptr, int monitor_index); extern int video_get_type_monitor(int monitor_index); @@ -288,12 +301,8 @@ extern uint8_t video_force_resize_get_monitor(int monitor_index); extern void video_force_resize_set_monitor(uint8_t res, int monitor_index); extern void video_update_timing(void); -extern void loadfont_ex(char *fn, int format, int offset); -extern void loadfont(char *fn, int format); - -extern int get_actual_size_x(void); -extern int get_actual_size_y(void); - +#define LOAD_FONT_NO_OFFSET 0 +extern void video_load_font(char *fn, int format, int offset); extern uint32_t video_color_transform(uint32_t color); #define video_inform(type, video_timings_ptr) video_inform_monitor(type, video_timings_ptr, monitor_index_global) @@ -336,6 +345,7 @@ extern const device_t mach64ct_device; extern const device_t mach64ct_device_onboard; extern const device_t mach64vt_device; extern const device_t mach64vt2_device; +extern const device_t mach64vt3_onboard_device; /* ATi 18800 */ extern const device_t ati18800_wonder_device; diff --git a/src/machine/m_amstrad.c b/src/machine/m_amstrad.c index 8e52bd4889f..8e4a16c60af 100644 --- a/src/machine/m_amstrad.c +++ b/src/machine/m_amstrad.c @@ -784,7 +784,7 @@ const device_config_t vid_1512_config[] = { }; const device_t vid_1512_device = { - .name = "Amstrad PC1512 (video)", + .name = "Amstrad PC1512 (Video)", .internal_name = "vid_1512", .flags = 0, .local = 0, @@ -985,7 +985,7 @@ const device_config_t vid_1640_config[] = { }; const device_t vid_1640_device = { - .name = "Amstrad PC1640 (video)", + .name = "Amstrad PC1640 (Video)", .internal_name = "vid_1640", .flags = 0, .local = 0, @@ -1911,7 +1911,7 @@ const device_config_t vid_200_config[] = { }; const device_t vid_200_device = { - .name = "Amstrad PC200 (video)", + .name = "Amstrad PC200 (Video)", .internal_name = "vid_200", .flags = 0, .local = 0, @@ -2019,7 +2019,7 @@ const device_config_t vid_ppc512_config[] = { }; const device_t vid_ppc512_device = { - .name = "Amstrad PPC512 (video)", + .name = "Amstrad PPC512 (Video)", .internal_name = "vid_ppc512", .flags = 0, .local = 0, @@ -2036,7 +2036,7 @@ const device_config_t vid_pc2086_config[] = { // clang-format off { .name = "language", - .description = "BIOS language", + .description = "BIOS Language", .type = CONFIG_SELECTION, .default_string = NULL, .default_int = 7, @@ -2054,7 +2054,7 @@ const device_config_t vid_pc2086_config[] = { }; const device_t vid_pc2086_device = { - .name = "Amstrad PC2086", + .name = "Amstrad PC2086 (Video)", .internal_name = "vid_pc2086", .flags = 0, .local = 0, @@ -2071,7 +2071,7 @@ const device_config_t vid_pc3086_config[] = { // clang-format off { .name = "language", - .description = "BIOS language", + .description = "BIOS Language", .type = CONFIG_SELECTION, .default_string = NULL, .default_int = 7, @@ -2089,7 +2089,7 @@ const device_config_t vid_pc3086_config[] = { }; const device_t vid_pc3086_device = { - .name = "Amstrad PC3086", + .name = "Amstrad PC3086 (Video)", .internal_name = "vid_pc3086", .flags = 0, .local = 0, @@ -3020,7 +3020,7 @@ machine_amstrad_init(const machine_t *model, int type) if (gfxcard[0] == VID_INTERNAL) switch (type) { case AMS_PC1512: - loadfont("roms/machines/pc1512/40078", 8); + video_load_font("roms/machines/pc1512/40078", FONT_FORMAT_PC1512_T1000, LOAD_FONT_NO_OFFSET); device_context(&vid_1512_device); ams->language = device_get_config_int("language"); vid_init_1512(ams); @@ -3029,7 +3029,7 @@ machine_amstrad_init(const machine_t *model, int type) break; case AMS_PPC512: - loadfont("roms/machines/ppc512/40109", 1); + video_load_font("roms/machines/ppc512/40109", FONT_FORMAT_PC200, LOAD_FONT_NO_OFFSET); device_context(&vid_ppc512_device); ams->language = device_get_config_int("language"); vid_init_200(ams); @@ -3038,7 +3038,7 @@ machine_amstrad_init(const machine_t *model, int type) break; case AMS_PC1640: - loadfont(FONT_IBM_MDA_437_PATH, 0); + video_load_font(FONT_IBM_MDA_437_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); device_context(&vid_1640_device); ams->language = device_get_config_int("language"); vid_init_1640(ams); @@ -3047,7 +3047,7 @@ machine_amstrad_init(const machine_t *model, int type) break; case AMS_PC200: - loadfont("roms/machines/pc200/40109", 1); + video_load_font("roms/machines/pc200/40109", FONT_FORMAT_PC200, LOAD_FONT_NO_OFFSET); device_context(&vid_200_device); ams->language = device_get_config_int("language"); vid_init_200(ams); diff --git a/src/machine/m_at_286.c b/src/machine/m_at_286.c index 499f0653ac1..ad36e3245ad 100644 --- a/src/machine/m_at_286.c +++ b/src/machine/m_at_286.c @@ -938,7 +938,7 @@ machine_at_pc7286_init(const machine_t *model) machine_at_common_init_ex(model, 2); if (gfxcard[0] == VID_INTERNAL) - device_add(&gd5401_onboard_device); + device_add(machine_get_vid_device(machine)); device_add_params(&dw90c50_device, (void *) DW90C50_IDE); device_add(&vl82c113_device); /* The keyboard controller is part of the VL82c113. */ @@ -1161,7 +1161,7 @@ machine_at_spc4620p_init(const machine_t *model) return ret; if (gfxcard[0] == VID_INTERNAL) - device_add(&ati28800k_spc4620p_device); + device_add(machine_get_vid_device(machine)); machine_at_scat_init(model, 1, 1); diff --git a/src/machine/m_at_386sx.c b/src/machine/m_at_386sx.c index ae9870c77e5..9ad29e2e87d 100644 --- a/src/machine/m_at_386sx.c +++ b/src/machine/m_at_386sx.c @@ -750,7 +750,7 @@ machine_at_wd76c10_init(const machine_t *model) machine_at_common_init_ex(model, 2); if (gfxcard[0] == VID_INTERNAL) - device_add(¶dise_wd90c11_megapc_device); + device_add(machine_get_vid_device(machine)); device_add_params(machine_get_kbc_device(machine), (void *) model->kbc_params); diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index 0c4be22497f..713ab09c05c 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -307,6 +307,167 @@ machine_at_spitfire_init(const machine_t *model) return ret; } +static const device_config_t ms6117_config[] = { + // clang-format off + { + .name = "bios", + .description = "BIOS Version", + .type = CONFIG_BIOS, + .default_string = "ms6117a", + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { + { + .name = "AMIBIOS 6 (071595) - Revision 2.0", + .internal_name = "ms6117a", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 131072, + .files = { "roms/machines/ms6117/A617MS20.ROM", "" } + }, + { + .name = "AMIBIOS 6 (071595) - Revision 1.10j (Japanese)", + .internal_name = "ms6117aj", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 131072, + .files = { "roms/machines/ms6117/A617J110.ROM", "" } + }, + { + .name = "AMIBIOS 6 (071595) - Revision 3.11sc (Simplified Chinese)", + .internal_name = "ms6117asc", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 131072, + .files = { "roms/machines/ms6117/A617C311.ROM", "" } + }, + { + .name = "AMIBIOS 6 (071595) - Revision 4.10tc (Traditional Chinese)", + .internal_name = "ms6117atc", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 131072, + .files = { "roms/machines/ms6117/A617C410.ROM", "" } + }, + { + .name = "Award Modular BIOS v4.51PG - Revision 3.2", + .internal_name = "ms6117w", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 262144, + .files = { "roms/machines/ms6117/W617MS32.BIN", "" } + }, + { + .name = "Award Modular BIOS v4.51PG - Revision 3.2 [Patched for larger drives]", + .internal_name = "ms6117wp", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 262144, + .files = { "roms/machines/ms6117/611732x_patched.BIN", "" } + }, + { + .name = "Award Modular BIOS v4.51PG - Revision 1.4 (Fujitsu-Siemens OEM)", + .internal_name = "ms6117wfs", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 131072, + .files = { "roms/machines/ms6117/AWARD 1.04 .BIN", "" } + }, + { + .name = "Award Modular BIOS v4.51PG - Revision 1.02 (LG IBM Multinet x7E)", + .internal_name = "ms6117wlg", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 262144, + .files = { "roms/machines/ms6117/BIOS.BIN", "" } + }, + { + .name = "Award Modular BIOS v4.51PG - Revision 1.5 (Viglen Vig67M)", + .internal_name = "ms6117wvi", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 131072, + .files = { "roms/machines/ms6117/w617v115.BIN", "" } + }, + { .files_no = 0 } + } + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t ms6117_device = { + .name = "MSI MS-6117", + .internal_name = "ms6117", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = ms6117_config +}; + +int +machine_at_ms6117_init(const machine_t *model) +{ + int ret = 0; + const char *fn; + + /* No ROMs available */ + if (!device_available(model->device)) + return ret; + + device_context(model->device); + fn = device_get_bios_file(machine_get_device(machine), device_get_config_bios("bios"), 0); + if (!strcmp(fn, "roms/machines/ms6117/W617MS32.BIN") || !strcmp(fn, "roms/machines/ms6117/611732x_patched.BIN") || !strcmp(fn, "roms/machines/ms6117/BIOS.BIN")) + ret = bios_load_linear(fn, 0x000c0000, 262144, 0); + else + ret = bios_load_linear(fn, 0x000e0000, 131072, 0); + device_context_restore(); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x10, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + + device_add(&i440lx_device); + device_add(&piix4e_device); + device_add_params(&w83977_device, (void *) (W83977TF | W83977_AMI | W83977_NO_NVR)); + + if (!strcmp(fn, "roms/machines/ms6117/W617MS32.BIN") || !strcmp(fn, "roms/machines/ms6117/611732x_patched.BIN") || !strcmp(fn, "roms/machines/ms6117/BIOS.BIN")) + device_add(&winbond_flash_w29c020_device); /* assumed */ + else + device_add(&winbond_flash_w29c011a_device); + + spd_register(SPD_TYPE_SDRAM, 0xF, 256); + + return ret; +} + int machine_at_ma30d_init(const machine_t *model) { @@ -344,6 +505,78 @@ machine_at_ma30d_init(const machine_t *model) } /* i440EX */ +int +machine_at_brio83xx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/brio83xx/QHL0700.rom", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + // Actual settings! + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 1, 2, 3, 4); /* Onboard */ + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); /* Onboard */ + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); /* Onboard */ + pci_register_slot(0x0F, PCI_CARD_NORMAL, 1, 2, 3, 4); /* Slot 01 */ + pci_register_slot(0x10, PCI_CARD_NORMAL, 2, 3, 4, 1); /* Slot 02 */ + pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); /* Slot 03 */ + pci_register_slot(0x14, PCI_CARD_VIDEO, 1, 2, 3, 4); /* Onboard */ + + if (gfxcard[0] == VID_INTERNAL) + device_add(&s3_trio64v2_dx_onboard_pci_device); + + device_add(&i440ex_device); + device_add(&piix4_device); + + device_add_params(&fdc37c67x_device, (void *) (FDC37XXX5)); + + /* Chip not quite confirmed, but this does operate fine. */ + device_add(&sst_flash_29ee020_device); + + spd_register(SPD_TYPE_SDRAM, 0x3, 256); + + return ret; +} + +int +machine_at_como_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/como/COMO.ROM", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x13, PCI_CARD_NORMAL, 1, 2, 3, 4); + + device_add(&i440ex_device); + device_add(&piix4e_device); + device_add_params(&fdc37m60x_device, (void*)(FDC37XXX2 | FDC37C93X_NO_NVR | FDC37XXXX_370)); + device_add(&intel_flash_bxt_device); + device_add(&lm78_device); + + if (sound_card_current[0] == SOUND_INTERNAL) + device_add(&cs4235_onboard_device); + + return ret; +} + int machine_at_p6i440e2_init(const machine_t *model) { @@ -425,16 +658,43 @@ static const device_config_t bx6_config[] = { .bios = { { .name = "Award Modular BIOS v4.51PG - Revision EG", - .internal_name = "bx6_eg", + .internal_name = "bx6", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/bx6/BX6_EG.BIN", "" } }, + { + .name = "Award Modular BIOS v4.51PG - Revision CW", + .internal_name = "bx6_CW", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 131072, + .files = { "roms/machines/bx6/BX6_CW.bin", "" } + }, + { + .name = "Award Modular BIOS v4.51PG - Revision GQ", + .internal_name = "bx6_GQ", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 131072, + .files = { "roms/machines/bx6/BX6_GQ.bin", "" } + }, + { + .name = "Award Modular BIOS v4.51PG - Revision JL", + .internal_name = "bx6_JL", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 131072, + .files = { "roms/machines/bx6/BX6_JL.bin", "" } + }, { .name = "Award Modular BIOS v4.51PG - Revision QS", - .internal_name = "bx6", + .internal_name = "bx6_qs", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, @@ -691,7 +951,16 @@ static const device_config_t ga686_config[] = { .files = { "roms/machines/686bx/31nologo.bin", "" } }, { - .name = "Award Modular BIOS v4.51PG - Revision F2a", + .name = "Award Modular BIOS v4.51PG - Revision F1", + .internal_name = "686bx_f1", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 262144, + .files = { "roms/machines/686bx/6BX.F1", "" } + }, + { + .name = "Award Modular BIOS v4.51PG - Revision F2a (Beta)", .internal_name = "686bx", .bios_type = BIOS_NORMAL, .files_no = 1, @@ -810,7 +1079,7 @@ static const device_config_t ms6119_config[] = { .files = { "roms/machines/ms6119/vig69m.212", "" } }, { - .name = "Award Modular BIOS v4.51PG - Revision 3.30b1 (LG IBM Multinet i x7G)", + .name = "Award Modular BIOS v4.51PG - Revision 3.30b1 (LG IBM Multinet x7G)", .internal_name = "lgibmx7g", .bios_type = BIOS_NORMAL, .files_no = 1, @@ -1057,8 +1326,8 @@ machine_at_p6sba_init(const machine_t *model) device_add_params(&w83977_device, (void *) (W83977TF | W83977_AMI | W83977_NO_NVR)); device_add(&intel_flash_bxt_device); spd_register(SPD_TYPE_SDRAM, 0x7, 256); - device_add(&w83781d_device); /* fans: CPU1, CPU2, Thermal Control; temperatures: unused, CPU1, CPU2 */ - hwm_values.voltages[1] = 3300; /* Seems to be the I/O voltage, reported as "CPUi/o" in the Leadtek BIOS and "CPU2" in the SuperMicro BIOS */ + device_add(&w83781d_device); /* fans: CPU1, CPU2, Thermal Control; temperatures: unused, CPU1, CPU2 */ + hwm_values.voltages[1] = 1500; /* potentially Vtt; Leadtek BIOS calls it CPUi/o; Supermicro BIOS calls it CPU2 and reads a voltage this low as N/A */ return ret; } @@ -1430,7 +1699,7 @@ static const device_config_t ms6199va_config[] = { .files = { "roms/machines/ms6199va/w6199vms.350", "" } }, { - .name = "Award Modular BIOS v4.51PG - Revision 2.0 (Compaq OEM)", + .name = "Award Modular BIOS v4.51PG - Revision 2.0 (Compaq ProSignia/Deskpro 693A)", .internal_name = "ms6199va_200", .bios_type = BIOS_NORMAL, .files_no = 1, @@ -1439,7 +1708,7 @@ static const device_config_t ms6199va_config[] = { .files = { "roms/machines/ms6199va/W6199VC8.BIN", "" } }, { - .name = "Award Modular BIOS v4.51PG - Revision 2.0 (Compaq OEM) [patched for large drives]", + .name = "Award Modular BIOS v4.51PG - Revision 2.0 (Compaq ProSignia/Deskpro 693A) [Patched for larger drives]", .internal_name = "ms6199va_200p", .bios_type = BIOS_NORMAL, .files_no = 1, @@ -1448,7 +1717,7 @@ static const device_config_t ms6199va_config[] = { .files = { "roms/machines/ms6199va/W6199VC8.PCD", "" } }, { - .name = "Award Modular BIOS v4.51PG - Revision 3.7 (Packard Bell OEM)", + .name = "Award Modular BIOS v4.51PG - Revision 3.7 (Packard Bell Phoenix)", .internal_name = "ms6199va_370", .bios_type = BIOS_NORMAL, .files_no = 1, diff --git a/src/machine/m_at_socket2.c b/src/machine/m_at_socket2.c index 8ea151f5300..d8fdd79f128 100644 --- a/src/machine/m_at_socket2.c +++ b/src/machine/m_at_socket2.c @@ -92,7 +92,7 @@ machine_at_acera1g_init(const machine_t *model) device_add(&ali1429g_device); if (gfxcard[0] == VID_INTERNAL) - device_add(&gd5428_onboard_device); + device_add(machine_get_vid_device(machine)); device_add_params(machine_get_kbc_device(machine), (void *) model->kbc_params); @@ -343,6 +343,7 @@ machine_at_valuepoint433_init(const machine_t *model) // hangs without the PS/2 machine_at_common_ide_init(model); device_add(&sis_85c461_device); + if (gfxcard[0] == VID_INTERNAL) device_add(&et4000w32_onboard_device); @@ -364,6 +365,33 @@ machine_at_valuepoint433_init(const machine_t *model) // hangs without the PS/2 } /* VLSI 82C480 */ +int +machine_at_monsoon_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined("roms/machines/monsoon/1009AC0_.BIO", + "roms/machines/monsoon/1009AC0_.BI1", 0x1c000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + device_add(&vl82c480_device); + device_add(&vl82c113_device); + + device_add(&ide_vlb_device); + device_add_params(&fdc37c6xx_device, (void *) (FDC37C651 | FDC37C6XX_IDE_PRI)); + + device_add(&intel_flash_bxt_device); + + if (gfxcard[0] == VID_INTERNAL) + device_add(machine_get_vid_device(machine)); + + return ret; +} + int machine_at_martin_init(const machine_t *model) { diff --git a/src/machine/m_at_socket370.c b/src/machine/m_at_socket370.c index ee75752db90..6627c709719 100644 --- a/src/machine/m_at_socket370.c +++ b/src/machine/m_at_socket370.c @@ -512,7 +512,7 @@ static const device_config_t ms6318_config[] = { .files = { "roms/machines/ms6318/ms-6318-ver5.bin", "" } }, { - .name = "Award Modular BIOS v6.00PG - Revision 1.8 (HP OEM)", + .name = "Award Modular BIOS v6.00PG - Revision 1.8 (HP Pavilion A7xx)", .internal_name = "ms6318_180", .bios_type = BIOS_NORMAL, .files_no = 1, @@ -521,7 +521,7 @@ static const device_config_t ms6318_config[] = { .files = { "roms/machines/ms6318/med2000v2.bin", "" } }, { - .name = "Award Modular BIOS v6.00PG - Revision 1.9 (HP OEM)", + .name = "Award Modular BIOS v6.00PG - Revision 1.9 (HP Pavilion A8xx)", .internal_name = "ms6318_190", .bios_type = BIOS_NORMAL, .files_no = 1, @@ -530,7 +530,7 @@ static const device_config_t ms6318_config[] = { .files = { "roms/machines/ms6318/med2000.bin", "" } }, { - .name = "Award Modular BIOS v6.00PG - Revision 2.02 (HP OEM)", + .name = "Award Modular BIOS v6.00PG - Revision 2.02 (HP Medion 2000A)", .internal_name = "ms6318_202", .bios_type = BIOS_NORMAL, .files_no = 1, @@ -539,7 +539,7 @@ static const device_config_t ms6318_config[] = { .files = { "roms/machines/ms6318/ms6318hp.bin", "" } }, { - .name = "Award Modular BIOS v6.00PG - Revision 1.3 (Medion OEM)", + .name = "Award Modular BIOS v6.00PG - Revision 1.3 (Medion MED 2000)", .internal_name = "ms6318_130", .bios_type = BIOS_NORMAL, .files_no = 1, @@ -548,7 +548,7 @@ static const device_config_t ms6318_config[] = { .files = { "roms/machines/ms6318/ms6318.bin", "" } }, { - .name = "Award Modular BIOS v6.00PG - Revision 7.51 (Medion OEM)", + .name = "Award Modular BIOS v6.00PG - Revision 7.51 (Medion MD6318)", .internal_name = "ms6318_751", .bios_type = BIOS_NORMAL, .files_no = 1, @@ -611,10 +611,9 @@ machine_at_ms6318_init(const machine_t *model) hwm_values.temperatures[1] += 2; /* System offset */ hwm_values.temperatures[2] = 0; /* unused */ - if (sound_card_current[0] == SOUND_INTERNAL) { + if (sound_card_current[0] == SOUND_INTERNAL) device_add(machine_get_snd_device(machine)); - device_add(&stac9708_device); - } + device_add(&vt1611a_device); /* for both VIA and CT5880 options */ return ret; } diff --git a/src/machine/m_at_socket7.c b/src/machine/m_at_socket7.c index 4715e72eb64..7261e2616ae 100644 --- a/src/machine/m_at_socket7.c +++ b/src/machine/m_at_socket7.c @@ -1211,7 +1211,7 @@ machine_at_pb810_init(const machine_t *model) pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); if (sound_card_current[0] == SOUND_INTERNAL) - device_add(&cs4237b_device); + machine_snd = device_add(machine_get_snd_device(machine)); device_add(&i430vx_device); device_add(&piix3_device); @@ -1484,6 +1484,40 @@ machine_at_ym430tx_init(const machine_t *model) return ret; } +int +machine_at_tx97xv_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/tx97xv/Bios.rom", + 0x000c0000, 262144, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init_ex(model, 2); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 1, 2, 3, 4); + pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4); /* PIIX4 */ + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_VIDEO, 1, 0, 0, 0); + + device_add(&i430tx_device); + device_add(&piix4_device); + device_add_params(&pc87307_device, (void *) (PCX730X_AMI | PCX7307_PC87307 | PCX730X_02E)); + device_add(&intel_flash_bxt_device); + spd_register(SPD_TYPE_SDRAM, 0x3, 128); + + if ((gfxcard[0] == VID_INTERNAL) && machine_get_vid_device(machine)) + device_add(machine_get_vid_device(machine)); + + return ret; +} + int machine_at_thunderbolt_init(const machine_t *model) { diff --git a/src/machine/m_at_socket7_3v.c b/src/machine/m_at_socket7_3v.c index c3672c8e618..a1ea769405c 100644 --- a/src/machine/m_at_socket7_3v.c +++ b/src/machine/m_at_socket7_3v.c @@ -158,7 +158,7 @@ machine_at_exp8551_init(const machine_t *model) } static void -machine_at_hpholly_gpio_init(void) +machine_at_holly_gpio_init(void) { uint32_t gpio = 0xffffe2ff; @@ -193,19 +193,19 @@ machine_at_hpholly_gpio_init(void) } int -machine_at_hpholly_init(const machine_t *model) /* HP Pavilion Holly, 7070/7090/5100/7100 */ +machine_at_holly_init(const machine_t *model) /* HP Pavilion Holly, 7070/7090/5100/7100 */ { int ret; - ret = bios_load_linear_combined("roms/machines/hpholly/1005CA2L.BIO", - "roms/machines/hpholly/1005CA2L.BI1", + ret = bios_load_linear_combined("roms/machines/holly/1005CA2L.BIO", + "roms/machines/holly/1005CA2L.BI1", 0x20000, 128); if (bios_only || !ret) return ret; machine_at_common_init_ex(model, 2); - machine_at_hpholly_gpio_init(); + machine_at_holly_gpio_init(); pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); diff --git a/src/machine/m_at_t3100e.c b/src/machine/m_at_t3100e.c index 4919f49751d..e13ec95303e 100644 --- a/src/machine/m_at_t3100e.c +++ b/src/machine/m_at_t3100e.c @@ -158,6 +158,7 @@ #include <86box/device.h> #include <86box/keyboard.h> #include <86box/rom.h> +#include <86box/video.h> #include "cpu.h" #include <86box/fdd.h> #include <86box/fdc.h> @@ -817,6 +818,7 @@ machine_at_t3100e_init(const machine_t *model) machine_at_common_ide_init(model); + video_reset(gfxcard[0]); device_add_params(machine_get_kbc_device(machine), (void *) model->kbc_params); if (fdc_current[0] == FDC_INTERNAL) diff --git a/src/machine/m_elt.c b/src/machine/m_elt.c index b965486d1ae..1f440bad204 100644 --- a/src/machine/m_elt.c +++ b/src/machine/m_elt.c @@ -33,9 +33,9 @@ #include #include #include +#include <86box/86box.h> #include <86box/timer.h> #include <86box/fdd.h> -#include <86box/86box.h> #include <86box/device.h> #include <86box/fdc.h> #include <86box/fdc_ext.h> diff --git a/src/machine/m_pcjr.c b/src/machine/m_pcjr.c index 78f7ba7107d..d26dae71fa1 100644 --- a/src/machine/m_pcjr.c +++ b/src/machine/m_pcjr.c @@ -848,7 +848,7 @@ static const device_config_t pcjr_config[] = { }; const device_t pcjr_device = { - .name = "IBM PCjr", + .name = "IBM PCjr (Video)", .internal_name = "pcjr", .flags = 0, .local = 0, @@ -897,7 +897,7 @@ machine_pcjr_init(UNUSED(const machine_t *model)) /* Initialize the video controller. */ video_reset(gfxcard[0]); - loadfont(FONT_IBM_MDA_437_PATH, 0); + video_load_font(FONT_IBM_MDA_437_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); device_context(&pcjr_device); pcjr_vid_init(pcjr); device_context_restore(); diff --git a/src/machine/m_v86p.c b/src/machine/m_v86p.c index 0be44de5332..1265173458c 100644 --- a/src/machine/m_v86p.c +++ b/src/machine/m_v86p.c @@ -77,9 +77,9 @@ machine_v86p_init(const machine_t *model) return ret; if (rom_id == 2) - loadfont("roms/machines/v86p/V86P.FON", 8); + video_load_font("roms/machines/v86p/V86P.FON", FONT_FORMAT_PC1512_T1000, LOAD_FONT_NO_OFFSET); else - loadfont("roms/machines/v86p/v86pfont.rom", 8); + video_load_font("roms/machines/v86p/v86pfont.rom", FONT_FORMAT_PC1512_T1000, LOAD_FONT_NO_OFFSET); machine_common_init(model); diff --git a/src/machine/m_xt.c b/src/machine/m_xt.c index e5906030c08..81c9eba7280 100644 --- a/src/machine/m_xt.c +++ b/src/machine/m_xt.c @@ -1704,27 +1704,6 @@ machine_xt_pcxt_init(const machine_t *model) static const device_config_t to16_config[] = { // clang-format off - { - .name = "bios", - .description = "BIOS Version", - .type = CONFIG_BIOS, - .default_string = "to16", - .default_int = 0, - .file_filter = NULL, - .spinner = { 0 }, - .bios = { - { - .name = "1.03", - .internal_name = "to16", - .bios_type = BIOS_NORMAL, - .files_no = 1, - .local = 0, - .size = 32768, - .files = { "roms/machines/to16/TO16_103.bin", "" } - }, - { .files_no = 0 } - }, - }, { .name = "rtc_port", .description = "Onboard RTC", @@ -1777,23 +1756,17 @@ const device_t to16_device = { int machine_xt_to16_init(const machine_t *model) { - int ret = 0; - int rtc_port = 0; - const char *fn; + int ret; - /* No ROMs available. */ - if (!device_available(model->device)) + ret = bios_load_linear("roms/machines/to16/TO16_103.bin", 0x000f8000, 32768, 0); + + if (bios_only || !ret) return ret; device_context(model->device); - rtc_port = machine_get_config_int("rtc_port"); - fn = device_get_bios_file(model->device, device_get_config_bios("bios"), 0); - ret = bios_load_linear(fn, 0x000f8000, 32768, 0); + int rtc_port = machine_get_config_int("rtc_port"); device_context_restore(); - if (bios_only || !ret) - return ret; - machine_xt_clone_init(model, 0); if (rtc_port != 0) @@ -2181,7 +2154,7 @@ machine_xt_maz1016_init(const machine_t *model) if (bios_only || !ret) return ret; - loadfont("roms/machines/maz1016/crt-8.bin", 0); + video_load_font("roms/machines/maz1016/crt-8.bin", FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); machine_xt_clone_init(model, 0); diff --git a/src/machine/m_xt_olivetti.c b/src/machine/m_xt_olivetti.c index 50a891e2c1c..d8cb819560d 100644 --- a/src/machine/m_xt_olivetti.c +++ b/src/machine/m_xt_olivetti.c @@ -2018,7 +2018,7 @@ m19_vid_init(m19_vid_t *vid) #endif /* OGC emulation part begin */ - loadfont("roms/machines/m19/MBM2764-30 8514 107 AB PCF3.BIN", 7); + video_load_font("roms/machines/m19/MBM2764-30 8514 107 AB PCF3.BIN", FONT_FORMAT_SIGMA, LOAD_FONT_NO_OFFSET); /* composite is not working yet */ vid->ogc.cga.composite = 0; // (display_type != CGA_RGB); vid->ogc.cga.revision = device_get_config_int("composite_type"); @@ -2119,7 +2119,7 @@ const device_config_t m19_vid_config[] = { }; const device_t m19_vid_device = { - .name = "Olivetti M19 graphics card", + .name = "Olivetti M19 (Video)", .internal_name = "m19_vid", .flags = 0, .local = 0, diff --git a/src/machine/m_xt_t1000.c b/src/machine/m_xt_t1000.c index 87899e7c6c3..8fd6925882c 100644 --- a/src/machine/m_xt_t1000.c +++ b/src/machine/m_xt_t1000.c @@ -846,7 +846,7 @@ machine_xt_t1000_init(const machine_t *model) t1000.ems_port_index = 7; /* EMS disabled */ /* Load the T1000 CGA Font ROM. */ - loadfont("roms/machines/t1000/t1000font.bin", 2); + video_load_font("roms/machines/t1000/t1000font.bin", FONT_FORMAT_CGA, LOAD_FONT_NO_OFFSET); /* * The ROM drive is optional. @@ -928,7 +928,7 @@ machine_xt_t1200_init(const machine_t *model) t1000.ems_port_index = 7; /* EMS disabled */ /* Load the T1000 CGA Font ROM. */ - loadfont("roms/machines/t1000/t1000font.bin", 2); + video_load_font("roms/machines/t1000/t1000font.bin", FONT_FORMAT_CGA, LOAD_FONT_NO_OFFSET); /* Map the EMS page frame */ for (uint8_t pg = 0; pg < 4; pg++) { diff --git a/src/machine/machine.c b/src/machine/machine.c index 30f979fd466..2db543cf2f3 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -69,7 +69,7 @@ machine_init_ex(int m) int ret = 0; if (!bios_only) { - machine_log("Initializing as \"%s\"\n", machine_getname()); + machine_log("Initializing as \"%s\"\n", machine_getname(machine)); machine_init_p1(); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 89f231ae5c7..2cd3db8a55d 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -49,7 +49,7 @@ const machine_filter_t machine_types[] = { { "[1992] 486SLC", MACHINE_TYPE_486SLC }, { "[1985] i386DX", MACHINE_TYPE_386DX }, { "[1989] i386DX/i486", MACHINE_TYPE_386DX_486 }, - { "[1992] i486 (Socket 168 and 1)", MACHINE_TYPE_486 }, + { "[1989] i486 (Socket 168 and 1)", MACHINE_TYPE_486 }, { "[1992] i486 (Socket 2)", MACHINE_TYPE_486_S2 }, { "[1994] i486 (Socket 3)", MACHINE_TYPE_486_S3 }, { "[1994] i486 (Socket 3 PCI)", MACHINE_TYPE_486_S3_PCI }, @@ -2685,7 +2685,7 @@ const machine_t machines[] = { .kbd_device = &keyboard_pc_xt_device, .fdc_device = NULL, .sio_device = NULL, - .vid_device = NULL, + .vid_device = NULL, /* Discrete onboard video card? */ .snd_device = NULL, .net_device = NULL }, @@ -4442,7 +4442,7 @@ const machine_t machines[] = { .kbd_device = NULL, .fdc_device = NULL, .sio_device = NULL, - .vid_device = NULL, + .vid_device = &gd5401_onboard_device, .snd_device = NULL, .net_device = NULL }, @@ -4884,7 +4884,7 @@ const machine_t machines[] = { .kbd_device = NULL, .fdc_device = NULL, .sio_device = NULL, - .vid_device = NULL, + .vid_device = &ati28800k_spc4620p_device, .snd_device = NULL, .net_device = NULL }, @@ -5373,7 +5373,7 @@ const machine_t machines[] = { .kbd_device = NULL, .fdc_device = NULL, .sio_device = NULL, - .vid_device = &tvga8900d_device, + .vid_device = &tvga8900d_device, /* Onboard variant not yet emulated */ .snd_device = NULL, .net_device = NULL }, @@ -5684,7 +5684,7 @@ const machine_t machines[] = { .kbd_device = NULL, .fdc_device = NULL, .sio_device = NULL, - .vid_device = NULL, + .vid_device = &if386jega_device, .snd_device = NULL, .net_device = NULL }, @@ -6043,7 +6043,7 @@ const machine_t machines[] = { .kbd_device = NULL, .fdc_device = NULL, .sio_device = NULL, - .vid_device = NULL, + .vid_device = ¶dise_wd90c11_megapc_device, .snd_device = NULL, .net_device = NULL }, @@ -8445,7 +8445,51 @@ const machine_t machines[] = { .kbd_device = NULL, .fdc_device = NULL, .sio_device = NULL, - .vid_device = NULL, + .vid_device = &et4000w32_onboard_device, + .snd_device = NULL, + .net_device = NULL + }, + /* Has a VLSI VL82C113A SCAMP Combination I/O which holds the KBC. */ + { + .name = "[VLSI 82C480] Intel Classic R/R Plus (Monsoon)", + .internal_name = "monsoon", + .type = MACHINE_TYPE_486_S2, + .chipset = MACHINE_CHIPSET_VLSI_VL82C480, + .init = machine_at_monsoon_init, + .p1_handler = machine_generic_p1_handler, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET3, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_IDE | MACHINE_VIDEO | MACHINE_APM, + .ram = { + .min = 2048, + .max = 32768, + .step = 2048 + }, + .nvrmask = 127, + .jumpered_ecp_dma = 0, + .default_jumpered_ecp_dma = -1, + .kbc_device = NULL, + .kbc_params = 0x00000000, + .kbc_p1 = 0x00000ce0, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .kbd_device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = &gd5428_vlb_onboard_device, .snd_device = NULL, .net_device = NULL }, @@ -10632,7 +10676,7 @@ const machine_t machines[] = { .fdc_device = NULL, .sio_device = NULL, .vid_device = &gd5430_onboard_pci_device, - .snd_device = &ess_1688_device, + .snd_device = &ess_1688_device, /* Onboard variant not yet emulated */ .net_device = NULL }, /* This has an AMIKey-2, which is an updated version of type 'H'. */ @@ -12069,7 +12113,7 @@ const machine_t machines[] = { .kbd_device = NULL, .fdc_device = NULL, .sio_device = NULL, - .vid_device = &s3_phoenix_vision864_pci_device, + .vid_device = &s3_phoenix_vision864_pci_device, /* Onboard variant not yet emulated */ .snd_device = NULL, .net_device = NULL }, @@ -13427,10 +13471,10 @@ const machine_t machines[] = { Command 0xA0 copyright string: (C)1994 AMI . */ { .name = "[i430FX] HP Pavilion 51xx/7070/7090/71xx (Holly)", - .internal_name = "hpholly", + .internal_name = "holly", .type = MACHINE_TYPE_SOCKET7_3V, .chipset = MACHINE_CHIPSET_INTEL_430FX, - .init = machine_at_hpholly_init, + .init = machine_at_holly_init, .p1_handler = machine_generic_p1_handler, .gpio_handler = NULL, .available_flag = MACHINE_AVAILABLE, @@ -14788,7 +14832,7 @@ const machine_t machines[] = { .cpu = { .package = CPU_PKG_SOCKET5_7, .block = CPU_BLOCK(CPU_K5, CPU_5K86, CPU_K6, CPU_K6_2, CPU_K6_2C, CPU_K6_3, CPU_K6_2P, - CPU_K6_3P, CPU_Cx6x86, CPU_Cx6x86MX, CPU_Cx6x86L), + CPU_K6_3P, CPU_Cx6x86, CPU_Cx6x86MX, CPU_Cx6x86L, CPU_WINCHIP, CPU_WINCHIP2), .min_bus = 50000000, .max_bus = 66666667, .min_voltage = 2800, @@ -15721,7 +15765,7 @@ const machine_t machines[] = { .fdc_device = NULL, .sio_device = NULL, .vid_device = NULL, - .snd_device = NULL, + .snd_device = &cs4237b_device, .net_device = NULL }, /* This has the AMIKey 'H' firmware, possibly AMIKey-2. Photos show it with a BestKey, so it @@ -15860,6 +15904,51 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* Has a National Semiconductor PC87307 Super I/O with on-chip KBC, which has one of these + firmwares: AMI '5' MegaKey, Phoenix MultiKey/42 1.37, or Phoenix MultiKey/42i 4.16. */ + { + .name = "[i430TX] ASUS TX97-XV (HP OEM)", + .internal_name = "tx97xv", + .type = MACHINE_TYPE_SOCKET7, + .chipset = MACHINE_CHIPSET_INTEL_430TX, + .init = machine_at_tx97xv_init, + .p1_handler = machine_generic_p1_handler, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET5_7, + .block = CPU_BLOCK_NONE, + .min_bus = 50000000, + .max_bus = 75000000, + .min_voltage = 2100, + .max_voltage = 3520, + .min_multi = 1.5, + .max_multi = 3.5 + }, + .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_USB | MACHINE_VIDEO, + .ram = { + .min = 8192, + .max = 262144, + .step = 8192 + }, + .nvrmask = 255, + .jumpered_ecp_dma = 0, + .default_jumpered_ecp_dma = -1, + .kbc_device = &kbc_at_device, + .kbc_params = KBC_VEN_AMI | 0x00004600, + .kbc_p1 = 0x00000cf0, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .kbd_device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = &mach64vt3_onboard_device, + .snd_device = NULL, + .net_device = NULL + }, /* This has the AMIKey KBC firmware, which is type 'F' (YM430TX is based on the TX97). */ { .name = "[i430TX] ASUS TX97", @@ -15999,7 +16088,7 @@ const machine_t machines[] = { .fdc_device = NULL, .sio_device = NULL, .vid_device = &s3_trio64v2_dx_onboard_pci_device, - .snd_device = &cs4236b_device, + .snd_device = &cs4236b_onboard_device, .net_device = &pcnet_am79c973_onboard_device }, /* This has the Phoenix MultiKey KBC firmware on the NSC Super I/O chip. */ @@ -18173,6 +18262,51 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[i440LX] MSI MS-6117", + .internal_name = "ms6117", + .type = MACHINE_TYPE_SLOT1, + .chipset = MACHINE_CHIPSET_INTEL_440LX, + .init = machine_at_ms6117_init, + .p1_handler = machine_generic_p1_handler, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 75000000, + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = 2.0, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP | MACHINE_BUS_USB, + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_USB, + .ram = { + .min = 8192, + .max = 786432, /* Manual thinks the maximum memory is 1024MB (256x4MB), but there is no 4th memory slot */ + .step = 8192 + }, + .nvrmask = 255, + .jumpered_ecp_dma = 0, + .default_jumpered_ecp_dma = -1, + .kbc_device = NULL, + .kbc_params = 0x00000000, + .kbc_p1 = 0x00000cf0, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = &ms6117_device, + .kbd_device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* Has a SM(S)C FDC37C67x Super I/O chip with on-chip KBC with Phoenix or AMIKey-2 KBC firmware. */ { @@ -18220,6 +18354,55 @@ const machine_t machines[] = { }, /* 440EX */ + /* Has a SM(S)C FDC37C675 Super I/O chip with on-chip KBC with Phoenix + MultiKey/42 (version 1.38) KBC firmware. */ + { + .name = "[i440EX] HP Brio 83xx", + .internal_name = "brio83xx", + .type = MACHINE_TYPE_SLOT1, + .chipset = MACHINE_CHIPSET_INTEL_440EX, + .init = machine_at_brio83xx_init, + .p1_handler = machine_generic_p1_handler, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK_NONE, + .min_bus = 66666667, + .max_bus = 66666667, + /* NOTE: Range not confirmed. */ + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 + }, + .bus_flags = MACHINE_PS2_AGP | MACHINE_BUS_USB, + .flags = MACHINE_IDE_DUAL | MACHINE_VIDEO | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, + .ram = { + /* PC manual says 128 MB max, but 256 MB confirmed to work + and 512 MB confirmed to not work. */ + .min = 8192, + .max = 262144, + .step = 8192 + }, + .nvrmask = 255, + .jumpered_ecp_dma = 0, + .default_jumpered_ecp_dma = -1, + .kbc_device = NULL, + .kbc_params = 0x00000000, + .kbc_p1 = 0x00000cf0, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .kbd_device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = &s3_trio64v2_dx_onboard_pci_device, + .snd_device = NULL, + .net_device = NULL + }, + /* Has a Winbond W83977TF Super I/O chip with on-chip KBC with AMIKey-2 KBC firmware. */ { @@ -18266,6 +18449,52 @@ const machine_t machines[] = { .net_device = NULL }, + /* Has a SMC FDC37M60x Super I/O chip with on-chip KBC with AMIKey-2 KBC + firmware. */ + { + .name = "[i440EX] TriGem Como", + .internal_name = "como", + .type = MACHINE_TYPE_SLOT1, + .chipset = MACHINE_CHIPSET_INTEL_440EX, + .init = machine_at_como_init, + .p1_handler = machine_generic_p1_handler, + .gpio_handler = machine_ap440fx_vs440fx_gpio_handler, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SLOT1, + .block = CPU_BLOCK(CPU_CYRIX3S), + .min_bus = 66666667, + .max_bus = 83333333, + .min_voltage = 2050, + .max_voltage = 3100, + .min_multi = 3.5, + .max_multi = 5.0 + }, + .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, + .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, + .ram = { + .min = 8192, + .max = 262144, + .step = 8192 + }, + .nvrmask = 255, + .jumpered_ecp_dma = 0, + .default_jumpered_ecp_dma = -1, + .kbc_device = NULL, + .kbc_params = 0x00000000, + .kbc_p1 = 0x00000cf0, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .kbd_device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = &cs4235_onboard_device, + .net_device = NULL + }, + /* 440BX */ /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC firmware. */ @@ -20427,13 +20656,7 @@ machine_count(void) } const char * -machine_getname(void) -{ - return (machines[machine].name); -} - -const char * -machine_getname_ex(int m) +machine_getname(int m) { return (machines[m].name); } @@ -20553,7 +20776,7 @@ machine_has_flags_ex(int flags) int ret = machine_has_flags(machine, flags); if (flags & MACHINE_PS2_KBC) { - if (machine_is_ps2) + if (machine_is_ps2 && (machines[machine].init != machine_at_pc5286_init)) ret |= MACHINE_PS2_KBC; else ret &= ~MACHINE_PS2_KBC; @@ -20661,7 +20884,7 @@ machine_get_machine_from_internal_name(const char *s) c++; } - return 0; + return -1; } int @@ -20670,12 +20893,6 @@ machine_has_mouse(void) return (machines[machine].flags & MACHINE_MOUSE); } -int -machine_is_sony(void) -{ - return (!strcmp(machines[machine].internal_name, "pcv90")); -} - const char * machine_get_nvr_name_ex(int m) { diff --git a/src/mem/mem.c b/src/mem/mem.c index 80803e6a2f4..91fa277be95 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -668,7 +668,6 @@ read_mem_b(uint32_t addr) { mem_mapping_t *map; uint8_t ret = 0xff; - int old_cycles = cycles; mem_logical_addr = addr; addr &= rammask; @@ -677,8 +676,6 @@ read_mem_b(uint32_t addr) if (map && map->read_b) ret = map->read_b(addr, map->priv); - resub_cycles(old_cycles); - return ret; } @@ -687,7 +684,6 @@ read_mem_w(uint32_t addr) { mem_mapping_t *map; uint16_t ret = 0xffff; - int old_cycles = cycles; mem_logical_addr = addr; addr &= rammask; @@ -703,8 +699,6 @@ read_mem_w(uint32_t addr) ret = map->read_b(addr, map->priv) | (map->read_b(addr + 1, map->priv) << 8); } - resub_cycles(old_cycles); - return ret; } @@ -712,7 +706,6 @@ void write_mem_b(uint32_t addr, uint8_t val) { mem_mapping_t *map; - int old_cycles = cycles; mem_logical_addr = addr; addr &= rammask; @@ -720,15 +713,12 @@ write_mem_b(uint32_t addr, uint8_t val) map = write_mapping[addr >> MEM_GRANULARITY_BITS]; if (map && map->write_b) map->write_b(addr, val, map->priv); - - resub_cycles(old_cycles); } void write_mem_w(uint32_t addr, uint16_t val) { mem_mapping_t *map; - int old_cycles = cycles; mem_logical_addr = addr; addr &= rammask; @@ -747,8 +737,6 @@ write_mem_w(uint32_t addr, uint16_t val) } } } - - resub_cycles(old_cycles); } uint8_t diff --git a/src/mem/rom.c b/src/mem/rom.c index 5798b4252ee..c2959e1b360 100644 --- a/src/mem/rom.c +++ b/src/mem/rom.c @@ -55,64 +55,54 @@ rom_log(const char *fmt, ...) # define rom_log(fmt, ...) #endif -void -rom_add_path(const char *path) +static void +add_path(rom_path_t *list, const char *path) { - char cwd[1024] = { 0 }; - - rom_path_t *rom_path = &rom_paths; - - if (rom_paths.path[0] != '\0') { - // Iterate to the end of the list. - while (rom_path->next != NULL) { - rom_path = rom_path->next; - } - - // Allocate the new entry. - rom_path = rom_path->next = calloc(1, sizeof(rom_path_t)); - } + rom_path_t *rom_path = calloc(1, sizeof(rom_path_t)); - // Save the path, turning it into absolute if needed. + /* Save the path, turning it into absolute if needed. */ if (!path_abs((char *) path)) { - plat_getcwd(cwd, sizeof(cwd)); - path_slash(cwd); - snprintf(rom_path->path, sizeof(rom_path->path), "%s%s", cwd, path); + plat_getcwd(rom_path->path, sizeof(rom_path->path)); + path_append_filename(rom_path->path, rom_path->path, path); } else { - snprintf(rom_path->path, sizeof(rom_path->path), "%s", path); + strncpy(rom_path->path, path, sizeof(rom_path->path) - 1); } - // Ensure the path ends with a separator. + /* Ensure the path ends with a separator. */ path_slash(rom_path->path); -} - -void -asset_add_path(const char *path) -{ - char cwd[1024] = { 0 }; - - rom_path_t *asset_path = &asset_paths; - if (asset_paths.path[0] != '\0') { - // Iterate to the end of the list. - while (asset_path->next != NULL) { - asset_path = asset_path->next; + /* Iterate to the end of the list. */ + if (list->path[0] != '\0') { + while (1) { + /* Check for duplicates. */ + if (!strcmp(list->path, rom_path->path)) { + free(rom_path); + return; + } + if (list->next == NULL) + break; + list = list->next; } - // Allocate the new entry. - asset_path = asset_path->next = calloc(1, sizeof(rom_path_t)); - } - - // Save the path, turning it into absolute if needed. - if (!path_abs((char *) path)) { - plat_getcwd(cwd, sizeof(cwd)); - path_slash(cwd); - snprintf(asset_path->path, sizeof(asset_path->path), "%s%s", cwd, path); + /* Add the new entry. */ + list->next = rom_path; } else { - snprintf(asset_path->path, sizeof(asset_path->path), "%s", path); + /* Set path on the first entry. */ + memcpy(list, rom_path, sizeof(rom_path_t)); + free(rom_path); } +} + +void +rom_add_path(const char *path) +{ + add_path(&rom_paths, path); +} - // Ensure the path ends with a separator. - path_slash(asset_path->path); +void +asset_add_path(const char *path) +{ + add_path(&asset_paths, path); } static int diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index 0943a9258a3..627535d53a2 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -19,6 +19,7 @@ list(APPEND net_sources network.c net_pcap.c net_slirp.c + net_switch.c net_dp8390.c net_3c501.c net_3c503.c @@ -57,18 +58,6 @@ if(WIN32) target_link_libraries(86Box ws2_32) endif() -if(NETSWITCH) - add_compile_definitions(USE_NETSWITCH) - list(APPEND net_sources - net_netswitch.c - netswitch.c - pb_common.c - pb_encode.c - pb_decode.c - networkmessage.pb.c - ) -endif() - if (UNIX) if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") set_source_files_properties(net_slirp.c PROPERTIES COMPILE_FLAGS "-I/usr/local/include") diff --git a/src/network/net_l80225.c b/src/network/net_l80225.c index 341799e57cf..6493edec6d9 100644 --- a/src/network/net_l80225.c +++ b/src/network/net_l80225.c @@ -34,17 +34,8 @@ l80225_mii_readw(uint16_t *regs, uint16_t addr) return 0; } -/* Readonly mask for MDI (PHY) registers */ -static const uint16_t tulip_mdi_mask[] = { - 0x0000, 0xffff, 0xffff, 0xffff, 0xc01f, 0xffff, 0xffff, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0fff, 0x0000, 0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - -}; - void l80225_mii_writew(uint16_t *regs, uint16_t addr, uint16_t val) { - regs[addr] = val & tulip_mdi_mask[addr]; + regs[addr] = val; } diff --git a/src/network/net_netswitch.c b/src/network/net_netswitch.c deleted file mode 100644 index 1cd0a81a71f..00000000000 --- a/src/network/net_netswitch.c +++ /dev/null @@ -1,497 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Network Switch network driver - * - * Authors: cold-brewed - * - * Copyright 2024 cold-brewed - */ -#include -#include -#include -#include -#include -#include -#include -#ifdef _WIN32 -# define WIN32_LEAN_AND_MEAN -# include -# include -#else -# include -#endif - -#define HAVE_STDARG_H -#include <86box/86box.h> -#include <86box/device.h> -#include <86box/thread.h> -#include <86box/timer.h> -#include <86box/network.h> -#include <86box/net_event.h> -#include "netswitch.h" -#include "networkmessage.pb.h" - -enum { - NET_EVENT_STOP = 0, - NET_EVENT_TX, - NET_EVENT_RX, - NET_EVENT_SWITCH, - NET_EVENT_MAX -}; - -/* Special define for the windows portion. We only need to poll up to - * NET_EVENT_SWITCH. NET_EVENT_SWITCH gives us a different NET_EVENT_MAX - * excluding the others, and windows does not like polling events that - * do not exist. */ -#define NET_EVENT_WIN_MAX NET_EVENT_SWITCH - -#define SWITCH_PKT_BATCH NET_QUEUE_LEN -/* In µs, how often to send a keepalive and perform connection maintenance */ -#define SWITCH_KEEPALIVE_INTERVAL 5000000 -/* In ms, how long until we consider a connection gone? */ -#define SWITCH_MAX_INTERVAL 10000 - -typedef struct { - void *nsconn; - uint8_t mac_addr[6]; - netcard_t *card; - thread_t *poll_tid; - net_evt_t tx_event; - net_evt_t stop_event; - netpkt_t pktv[SWITCH_PKT_BATCH]; - pc_timer_t stats_timer; - pc_timer_t maintenance_timer; - ns_rx_packet_t rx_packet; - char switch_type[16]; -#ifdef _WIN32 - HANDLE sock_event; -#endif -} net_netswitch_t; - -// Used for debugging, needs to be moved to an official location -void print_packet(const netpkt_t netpkt) { -#ifdef NET_SWITCH_LOG - if(netpkt.len == 0) { - net_switch_log("Something is wrong, len is %d\n", netpkt.len); - return; - } - /* Temporarily disable log suppression for packet dumping to allow specific formatting */ - pclog_toggle_suppr(); - uint8_t linebuff[17] = "\0"; - char src_mac_buf[32] = ""; - char dst_mac_buf[32] = ""; - for(int m_i=0; m_i < 6; m_i++) { - char src_octet[4]; - char dst_octet[4]; - snprintf(src_octet, sizeof(src_octet), "%02X%s", netpkt.data[m_i+6], m_i < 5 ? ":" : ""); - strncat(src_mac_buf, src_octet, sizeof (src_mac_buf) - 1); - - snprintf(dst_octet, sizeof(dst_octet), "%02X%s", netpkt.data[m_i], m_i < 5 ? ":" : ""); - strncat(dst_mac_buf, dst_octet, sizeof (dst_mac_buf) - 1); - } - net_switch_log("%s -> %s\n\n", src_mac_buf, dst_mac_buf); - - // Payload length (bytes 12-13 with zero index) - uint16_t payload_length = (netpkt.data[12] & 0xFF) << 8; - payload_length |= (netpkt.data[13] & 0xFF); - const uint16_t actual_length = netpkt.len - 14; - if(payload_length <= 1500) { - // 802.3 / 802.2 - net_switch_log("Payload length according to frame: %i\n", payload_length); - // remaining length of packet (len - 14) to calculate padding - net_switch_log("Actual payload length: %i\n", actual_length); - if(payload_length <=46 ) { - net_switch_log("Likely has %d bytes padding\n", actual_length - payload_length); - } - } else { - // Type II - net_switch_log("EtherType: 0x%04X\n", payload_length); - } - // actual packet size - net_switch_log("Full frame size: %i\n", netpkt.len); - net_switch_log("\n"); - - for(int i=0; i< netpkt.len; i++) { - - net_switch_log("%02x ", netpkt.data[i]); - if ((netpkt.data[i] < 0x20) || (netpkt.data[i] > 0x7e)) { - linebuff[i % 16] = '.'; - } else { - linebuff[i % 16] = netpkt.data[i]; - } - - if( (i+1) % 8 == 0) { - net_switch_log(" "); - } - - if( (i+1) % 16 == 0) { - net_switch_log("| %s |\n", (char *)linebuff); - linebuff[0] = '\0'; - } - - // last char? - if(i+1 == netpkt.len) { - const int togo = 16 - (i % 16); - for(int remaining = 0; remaining < togo-1; remaining++) { - // This would represent the byte display and the space - net_switch_log(" "); - } - // spacing between byte groupings - if(togo > 8) { - net_switch_log(" "); - } - linebuff[(i % 16) +1] = '\0'; - net_switch_log(" | %s", (char *)linebuff); - - for(int remaining = 0; remaining < togo-1; remaining++) { - // This would represent the remaining bytes on the right - net_switch_log(" "); - } - net_switch_log(" |\n"); - } - } - net_switch_log("\n"); - pclog_toggle_suppr(); -#endif /* NET_SWITCH_LOG*/ -} - -#ifdef ENABLE_NET_SWITCH_STATS -static void -stats_timer(void *priv) -{ - /* Get the device state structure. */ - net_netswitch_t *netswitch = priv; - const NSCONN *nsconn = netswitch->nsconn; - net_switch_log("Max (frame / packet) TX (%zu/%zu) RX (%zu/%zu)\n", - nsconn->stats.max_tx_frame, nsconn->stats.max_tx_packet, - nsconn->stats.max_rx_frame, nsconn->stats.max_rx_packet); - net_switch_log("Last ethertype (TX/RX) (%02x%02x/%02x%02x)\n", nsconn->stats.last_tx_ethertype[0], nsconn->stats.last_tx_ethertype[1], - nsconn->stats.last_rx_ethertype[0], nsconn->stats.last_rx_ethertype[1]); - net_switch_log("Packet totals (all/tx/rx/would fragment/max vec) (%zu/%zu/%zu/%zu/%i)\n", nsconn->stats.total_tx_packets + nsconn->stats.total_rx_packets, - nsconn->stats.total_tx_packets, nsconn->stats.total_rx_packets, nsconn->stats.total_fragments, nsconn->stats.max_vec); - net_switch_log("---\n"); - /* Restart the timer */ - timer_on_auto(&netswitch->stats_timer, 60000000); -} -#endif - -static void -maintenance_timer(void *priv) -{ - /* Get the device state structure. */ - net_netswitch_t *netswitch = (net_netswitch_t *) priv; - NSCONN *nsconn = (NSCONN *) netswitch->nsconn; - if (!ns_send_control(nsconn, MessageType_MESSAGE_TYPE_KEEPALIVE)) { - net_switch_log("Failed to send keepalive packet\n"); - } - const int64_t interval = ns_get_current_millis() - nsconn->last_packet_stamp; -// net_switch_log("Last packet time: %lld ago\n", interval); -// net_switch_log("Last packet time: %lld ago\n", interval); - - /* A timeout has likely occurred, try to fix the connection if type is REMOTE */ - if((interval > SWITCH_MAX_INTERVAL) && nsconn->switch_type == SWITCH_TYPE_REMOTE) { - /* FIXME: This is really rough, needs moar logic */ - nsconn->client_state = CONNECTING; - net_switch_log("We appear to be disconnected, attempting to reconnect\n"); - /* TODO: Proper connect function! This is duplicated code */ - if(!ns_send_control(nsconn, MessageType_MESSAGE_TYPE_CONNECT_REQUEST)) { - /* TODO: Failure */ - } - } - /* Restart the timer */ - timer_on_auto(&netswitch->maintenance_timer, SWITCH_KEEPALIVE_INTERVAL); -} - -/* Lots of #ifdef madness here thanks to the polling differences on windows */ -static void -net_netswitch_thread(void *priv) -{ - net_netswitch_t *net_netswitch = (net_netswitch_t *) priv; - NSCONN *nsconn = (NSCONN *) net_netswitch->nsconn; - bool status; - char switch_type[32]; - snprintf(switch_type, sizeof(switch_type), "%s", nsconn->switch_type == SWITCH_TYPE_REMOTE ? "Remote" : "Local"); - - net_switch_log("%s Net Switch: polling started.\n", switch_type); - -#ifdef _WIN32 - WSAEventSelect(ns_pollfd(net_netswitch->nsconn), net_netswitch->sock_event, FD_READ); - - HANDLE events[NET_EVENT_MAX]; - events[NET_EVENT_STOP] = net_event_get_handle(&net_netswitch->stop_event); - events[NET_EVENT_TX] = net_event_get_handle(&net_netswitch->tx_event); - events[NET_EVENT_RX] = net_netswitch->sock_event; - - bool run = true; -#else - struct pollfd pfd[NET_EVENT_MAX]; - pfd[NET_EVENT_STOP].fd = net_event_get_fd(&net_netswitch->stop_event); - pfd[NET_EVENT_STOP].events = POLLIN | POLLPRI; - - pfd[NET_EVENT_TX].fd = net_event_get_fd(&net_netswitch->tx_event); - pfd[NET_EVENT_TX].events = POLLIN | POLLPRI; - - pfd[NET_EVENT_RX].fd = ns_pollfd(net_netswitch->nsconn); - pfd[NET_EVENT_RX].events = POLLIN | POLLPRI; -#endif - -#ifdef _WIN32 - while (run) { - int ret = WaitForMultipleObjects(NET_EVENT_WIN_MAX, events, FALSE, INFINITE); - - switch (ret - WAIT_OBJECT_0) { -#else - while (1) { - poll(pfd, NET_EVENT_MAX, -1); -#endif - -#ifdef _WIN32 - case NET_EVENT_STOP: - net_event_clear(&net_netswitch->stop_event); - run = false; - break; - case NET_EVENT_TX: -#else - if (pfd[NET_EVENT_STOP].revents & POLLIN) { - net_event_clear(&net_netswitch->stop_event); - break; - } - if (pfd[NET_EVENT_TX].revents & POLLIN) { -#endif - net_event_clear(&net_netswitch->tx_event); - - const int packets = network_tx_popv(net_netswitch->card, net_netswitch->pktv, SWITCH_PKT_BATCH); - if (packets > nsconn->stats.max_vec) { - nsconn->stats.max_vec = packets; - } - for (int i = 0; i < packets; i++) { - // net_switch_log("%d packet(s) to send\n", packets); -#if defined(NET_PRINT_PACKET_TX) || defined(NET_PRINT_PACKET_ALL) - data_packet_info_t packet_info = get_data_packet_info(&net_netswitch->pktv[i], net_netswitch->mac_addr); - /* Temporarily disable log suppression for packet logging */ - pclog_toggle_suppr(); - net_switch_log("%s Net Switch: TX: %s\n", switch_type, packet_info.printable); - pclog_toggle_suppr(); - print_packet(net_netswitch->pktv[i]); -#endif - /* Only send if we're in a connected state (always true for local) */ - if(ns_connected(net_netswitch->nsconn)) { - const ssize_t nc = ns_send_pb(net_netswitch->nsconn, &net_netswitch->pktv[i], 0); - if (nc < 1) { - perror("Got"); - net_switch_log("%s Net Switch: Problem, no bytes sent. Got back %i\n", switch_type, nc); - } - } - } -#ifdef _WIN32 - break; - case NET_EVENT_RX: -#else - } - if (pfd[NET_EVENT_RX].revents & POLLIN) { -#endif - - /* Packets are available for reading */ - status = ns_recv_pb(net_netswitch->nsconn, &net_netswitch->rx_packet, NET_MAX_FRAME, 0); - if (!status) { - net_switch_log("Receive packet failed. Skipping.\n"); - continue; - } - - /* These types are handled in the backend and don't need to be considered */ - if (is_control_packet(&net_netswitch->rx_packet) || is_fragment_packet(&net_netswitch->rx_packet)) { - continue; - } - data_packet_info_t packet_info = get_data_packet_info(&net_netswitch->rx_packet.pkt, net_netswitch->mac_addr); -#if defined(NET_PRINT_PACKET_RX) || defined(NET_PRINT_PACKET_ALL) - print_packet(net_netswitch->rx_packet.pkt); -#endif - /* - * Accept packets that are - * Unicast for us - * Broadcasts that are not from us - * All other packets *if* promiscuous mode is enabled (excluding our own) - */ - if (packet_info.is_packet_for_me || (packet_info.is_broadcast && !packet_info.is_packet_from_me)) { - /* Temporarily disable log suppression for packet logging */ - pclog_toggle_suppr(); - net_switch_log("%s Net Switch: RX: %s\n", switch_type, packet_info.printable); - pclog_toggle_suppr(); - network_rx_put_pkt(net_netswitch->card, &net_netswitch->rx_packet.pkt); - } else if (packet_info.is_packet_from_me) { - net_switch_log("%s Net Switch: Got my own packet... ignoring\n", switch_type); - } else { - /* Not our packet. Pass it along if promiscuous mode is enabled. */ - if (ns_flags(net_netswitch->nsconn) & FLAGS_PROMISC) { - net_switch_log("%s Net Switch: Got packet from %s (not mine, promiscuous is set, getting)\n", switch_type, packet_info.src_mac_h); - network_rx_put_pkt(net_netswitch->card, &net_netswitch->rx_packet.pkt); - } else { - net_switch_log("%s Net Switch: RX: %s (not mine, dest %s != %s, promiscuous not set, ignoring)\n", switch_type, packet_info.printable, packet_info.dest_mac_h, packet_info.my_mac_h); - } - } -#ifdef _WIN32 - break; - } -#else - } -#endif - } - - net_switch_log("%s Net Switch: polling stopped.\n", switch_type); -} - -void -net_netswitch_error(char *errbuf, const char *message) { - strncpy(errbuf, message, NET_DRV_ERRBUF_SIZE); - net_switch_log("Net Switch: %s\n", message); -} - -void * -net_netswitch_init(const netcard_t *card, const uint8_t *mac_addr, void *priv, char *netdrv_errbuf) -{ - net_switch_log("Net Switch: Init\n"); - - netcard_conf_t *netcard = (netcard_conf_t *) priv; - - ns_flags_t flags = FLAGS_NONE; - ns_type_t switch_type; - - const int net_type = netcard->net_type; - if(net_type == NET_TYPE_NRSWITCH) { - net_switch_log("Switch type: Remote\n"); - switch_type = SWITCH_TYPE_REMOTE; - } else if (net_type == NET_TYPE_NMSWITCH) { - net_switch_log("Switch type: Local Multicast\n"); - switch_type = SWITCH_TYPE_LOCAL; - if(netcard->promisc_mode) { - flags |= FLAGS_PROMISC; - } - } else { - net_switch_log("Failed: Unknown net switch type %d\n", net_type); - return NULL; - } - - // FIXME: Only here during dev. This would be an error otherwise (hostname not specified) - if(strlen(netcard->nrs_hostname) == 0) { - strncpy(netcard->nrs_hostname, "127.0.0.1", 128 - 1); - } - - net_netswitch_t *net_netswitch = calloc(1, sizeof(net_netswitch_t)); - net_netswitch->card = (netcard_t *) card; - memcpy(net_netswitch->mac_addr, mac_addr, sizeof(net_netswitch->mac_addr)); - snprintf(net_netswitch->switch_type, sizeof(net_netswitch->switch_type), "%s", net_type == NET_TYPE_NRSWITCH ? "Remote" : "Local"); - -// net_switch_log("%s Net Switch: mode: %d, group %d, hostname %s len %lu\n", net_netswitch->switch_type, netcard->promisc_mode, netcard->switch_group, netcard->nrs_hostname, strlen(netcard->nrs_hostname)); - - struct ns_open_args ns_args; - ns_args.type = switch_type; - /* Setting FLAGS_PROMISC here lets all packets through except the ones from us */ - ns_args.flags = flags; - /* This option sets which switch group you want to be a part of. - * Functionally equivalent to being plugged into a different switch */ - ns_args.group = netcard->switch_group; - /* You could also set the client_id here. If 0, it will be generated. */ - ns_args.client_id = 0; - memcpy(ns_args.mac_addr, net_netswitch->mac_addr, 6); - /* The remote switch hostname */ - strncpy(ns_args.nrs_hostname, netcard->nrs_hostname, sizeof(ns_args.nrs_hostname) - 1); - ns_args.nrs_hostname[127] = 0x00; - - net_switch_log("%s Net Switch: Starting up virtual switch with group %d, flags %d\n", net_netswitch->switch_type, ns_args.group, ns_args.flags); - - if ((net_netswitch->nsconn = ns_open(&ns_args)) == NULL) { - char buf[NET_DRV_ERRBUF_SIZE]; - /* We're using some errnos for our own purposes */ - switch (errno) { - case EFAULT: - snprintf(buf, NET_DRV_ERRBUF_SIZE, "Unable to open switch group %d: Cannot resolve remote switch hostname %s", ns_args.group, ns_args.nrs_hostname); - break; - default: - snprintf(buf, NET_DRV_ERRBUF_SIZE, "Unable to open switch group %d (%s)", ns_args.group, strerror(errno)); - break; - - } - net_netswitch_error(netdrv_errbuf, buf); - free(net_netswitch); - return NULL; - } - - for (int i = 0; i < SWITCH_PKT_BATCH; i++) { - net_netswitch->pktv[i].data = calloc(1, NET_MAX_FRAME); - } - net_netswitch->rx_packet.pkt.data = calloc(1, NET_MAX_FRAME); - - net_event_init(&net_netswitch->tx_event); - net_event_init(&net_netswitch->stop_event); -#ifdef _WIN32 - net_netswitch->sock_event = CreateEvent(NULL, FALSE, FALSE, NULL); -#endif - net_netswitch->poll_tid = thread_create(net_netswitch_thread, net_netswitch); - - /* Add the timers */ -#ifdef ENABLE_NET_SWITCH_STATS - timer_add(&net_netswitch->stats_timer, stats_timer, net_netswitch, 0); - timer_on_auto(&net_netswitch->stats_timer, 5000000); -#endif - timer_add(&net_netswitch->maintenance_timer, maintenance_timer, net_netswitch, 0); - timer_on_auto(&net_netswitch->maintenance_timer, SWITCH_KEEPALIVE_INTERVAL); - - /* Send join message. Return status not checked here. */ - ns_send_control(net_netswitch->nsconn, MessageType_MESSAGE_TYPE_JOIN); - - return net_netswitch; -} - -void -net_netswitch_in_available(void *priv) -{ - net_netswitch_t *net_netswitch = (net_netswitch_t *) priv; - net_event_set(&net_netswitch->tx_event); -} - -void -net_netswitch_close(void *priv) -{ - if (priv == NULL) - return; - - net_netswitch_t *net_netswitch = (net_netswitch_t *) priv; - - net_switch_log("%s Net Switch: closing.\n", net_netswitch->switch_type); - - /* Tell the thread to terminate. */ - net_event_set(&net_netswitch->stop_event); - - /* Wait for the thread to finish. */ - net_switch_log("%s Net Switch: waiting for thread to end...\n", net_netswitch->switch_type); - thread_wait(net_netswitch->poll_tid); - net_switch_log("%s Net Switch: thread ended\n", net_netswitch->switch_type); - - for (int i = 0; i < SWITCH_PKT_BATCH; i++) { - free(net_netswitch->pktv[i].data); - } - free(net_netswitch->rx_packet.pkt.data); - - net_event_close(&net_netswitch->tx_event); - net_event_close(&net_netswitch->stop_event); - -#ifdef _WIN32 - WSACleanup(); -#endif - - ns_close(net_netswitch->nsconn); - free(net_netswitch); -} - -const netdrv_t net_netswitch_drv = { - .notify_in = &net_netswitch_in_available, - .init = &net_netswitch_init, - .close = &net_netswitch_close, - .priv = NULL, -}; diff --git a/src/network/net_pcnet.c b/src/network/net_pcnet.c index 0c97d1078ad..2d9aa88bbf6 100644 --- a/src/network/net_pcnet.c +++ b/src/network/net_pcnet.c @@ -3317,7 +3317,7 @@ const device_t pcnet_am79c973_device = { }; const device_t pcnet_am79c973_onboard_device = { - .name = "AMD PCnet-FAST III", + .name = "AMD PCnet-FAST III (On-Board)", .internal_name = "pcnetfast_onboard", .flags = DEVICE_PCI, .local = DEV_AM79C973 | 0x0100, diff --git a/src/network/net_switch.c b/src/network/net_switch.c new file mode 100644 index 00000000000..5fc3a209178 --- /dev/null +++ b/src/network/net_switch.c @@ -0,0 +1,551 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Network Switch network driver. + * + * Authors: RichardG, + * + * Copyright 2026 RichardG. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef _WIN32 +# define WIN32_LEAN_AND_MEAN +# include +# include +# include +# include +# define IFF_POINTOPOINT IFF_POINTTOPOINT +#else +# include +# include +# include +# include +# include +# include +# include +# include +#endif +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/plat.h> +#include <86box/thread.h> +#include <86box/timer.h> +#include <86box/network.h> +#include <86box/machine.h> +#include <86box/ini.h> +#include <86box/config.h> +#include <86box/net_event.h> +#include <86box/bswap.h> + +#define SWITCH_PKT_BATCH NET_QUEUE_LEN + +#define SWITCH_MULTICAST_GROUP 0xefff5656 /* 239.255.86.86 */ +#define SWITCH_MULTICAST_PORT 8086 + +enum { + NET_EVENT_STOP = 0, + NET_EVENT_TX, + NET_EVENT_RX, + NET_EVENT_MAX +}; + +typedef union { + struct sockaddr sa; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; +} net_switch_sockaddr_t; + +typedef struct net_switch_hostaddr_t { + struct net_switch_hostaddr_t *next; + net_switch_sockaddr_t addr; + net_switch_sockaddr_t addr_tx; + int socket_tx; +} net_switch_hostaddr_t; + +typedef struct net_switch_t { + int socket_rx; + net_switch_hostaddr_t *hostaddrs; + uint16_t port_out; + + uint8_t promisc; + union { + uint8_t mac_addr[6]; + uint64_t mac_addr_u64; + }; + netcard_t * card; /* netcard attached to us */ + thread_t * poll_tid; + net_evt_t tx_event; + net_evt_t stop_event; + netpkt_t pkt; + netpkt_t pkt_tx_v[SWITCH_PKT_BATCH]; + int during_tx; + int recv_on_tx; +#ifdef _WIN32 + HANDLE sock_event; +#endif +} net_switch_t; + +#ifdef ENABLE_SWITCH_LOG +int switch_do_log = ENABLE_SWITCH_LOG; + +static void +netswitch_log(const char *fmt, ...) +{ + va_list ap; + + if (switch_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define netswitch_log(fmt, ...) +#endif + +static void +net_switch_in_available(void *priv) +{ + net_switch_t *netswitch = (net_switch_t *) priv; + net_event_set(&netswitch->tx_event); +} + +static unsigned int +net_switch_add_hostaddr(net_switch_t *netswitch, net_switch_sockaddr_t *addr, net_switch_sockaddr_t *broadcast, net_switch_sockaddr_t *netmask, unsigned int flags) +{ + if (!addr || !(flags & IFF_UP)) + return 0; + + /* Iterate to the end of the list. */ + net_switch_hostaddr_t **p = &netswitch->hostaddrs; + for (; *p; p = &(*p)->next) { + /* Check for duplicates. */ + switch (addr->sa.sa_family) { + case AF_INET: + if ((*p)->addr.sin.sin_addr.s_addr == addr->sin.sin_addr.s_addr) + return 0; + break; +#ifdef UNUSED + case AF_INET6: + if (AS_U64((*p)->addr.sin6.sin6_addr.s6_addr[0]) == AS_U64(addr->sin6.sin6_addr.s6_addr[0]) && + AS_U64((*p)->addr.sin6.sin6_addr.s6_addr[8]) == AS_U64(addr->sin6.sin6_addr.s6_addr[8])) + return 0; + break; +#endif + default: + return 0; + } + } + + /* Handle address. */ + net_switch_hostaddr_t *hostaddr = (net_switch_hostaddr_t *) calloc(1, sizeof(net_switch_hostaddr_t)); + hostaddr->socket_tx = -1; + unsigned int ret = 1; + if (addr->sa.sa_family == AF_INET) { +#ifdef ENABLE_SWITCH_LOG + char buf[INET_ADDRSTRLEN]; + buf[0] = '\0'; + inet_ntop(addr->sin.sin_family, &addr->sin.sin_addr.s_addr, buf, sizeof(buf)); +#endif + + /* Initialize transmit socket for this interface. */ + hostaddr->socket_tx = socket(addr->sin.sin_family, SOCK_DGRAM, 0); + if (hostaddr->socket_tx < 0) { + netswitch_log("Network Switch: could not initialize transmit socket for interface %s\n", buf); + goto fail; + } + + /* Initialize addresses. */ + memcpy(&hostaddr->addr.sin, &addr->sin, sizeof(struct sockaddr_in)); + hostaddr->addr_tx.sin.sin_family = addr->sin.sin_family; + hostaddr->addr_tx.sin.sin_port = netswitch->port_out; + + /* The problem with multicasting through multiple interfaces is loopback, in which + all copies of the datagram get reflected back to us and to other instances on the + same host. Disabling IP_MULTICAST_LOOP on all but one transmit socket can mitigate + that, but not on Windows where that option applies to the receive socket, so we + instead disable loopback on all multicast sockets and use a broadcast for loopback. */ + if ((flags & (IFF_MULTICAST | IFF_LOOPBACK)) == IFF_MULTICAST) { + /* Set multicast interface for the transmit socket. */ + if (setsockopt(hostaddr->socket_tx, IPPROTO_IP, IP_MULTICAST_IF, (char *) &hostaddr->addr.sin.sin_addr.s_addr, sizeof(hostaddr->addr.sin.sin_addr.s_addr)) < 0) { + netswitch_log("Network Switch: could not configure multicast on interface %s\n", buf); + goto broadcast; + } + + /* Join IPv4 multicast group. */ + struct ip_mreq mreq = { + .imr_multiaddr = { .s_addr = htonl(SWITCH_MULTICAST_GROUP) }, + .imr_interface = { .s_addr = hostaddr->addr.sin.sin_addr.s_addr } + }; + if (setsockopt(netswitch->socket_rx, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq)) < 0) { + netswitch_log("Network Switch: could not join multicast group on interface %s\n", buf); + goto broadcast; + } + + /* Destination address is multicast to our group. */ + hostaddr->addr_tx.sin.sin_addr.s_addr = mreq.imr_multiaddr.s_addr; + + /* Disable multicast loopback on non-Windows platforms. (no harm on Windows) */ + int val = 0; + setsockopt(hostaddr->socket_tx, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &val, sizeof(val)); + + netswitch_log("Network Switch: added multicast interface %s", buf); + } else { +broadcast: + /* Determine destination address. */ + if (flags & IFF_LOOPBACK) { + /* Loopback interfaces don't advertise broadcast support and therefore + the broadcast address is invalid, so we build one from the netmask. */ + hostaddr->addr_tx.sin.sin_addr.s_addr = hostaddr->addr.sin.sin_addr.s_addr | (netmask ? ~netmask->sin.sin_addr.s_addr : htonl(0x00ffffff)); + ret = 0; + } else if (!(flags & (IFF_BROADCAST | IFF_POINTOPOINT)) || + !broadcast || !broadcast->sin.sin_addr.s_addr || + (broadcast->sin.sin_addr.s_addr == hostaddr->addr.sin.sin_addr.s_addr)) { + /* This interface is unicast-only or P2P with a bad peer address, nothing we can do. */ + netswitch_log("Network Switch: ignored %s interface %s\n", (flags & (IFF_LOOPBACK | IFF_BROADCAST)) ? "broadcast" : "unicast", buf); + goto fail; + } else { + /* Valid broadcast/peer address. */ + hostaddr->addr_tx.sin.sin_addr.s_addr = broadcast->sin.sin_addr.s_addr; + } + + /* Enable broadcast on the transmit socket if required. */ + if (flags & (IFF_LOOPBACK | IFF_BROADCAST)) { + int val = 1; + if (setsockopt(hostaddr->socket_tx, SOL_SOCKET, SO_BROADCAST, (char *) &val, sizeof(val)) < 0) { + netswitch_log("Network Switch: could not configure broadcast on interface %s\n", buf); + goto fail; + } + } + + netswitch_log("Network Switch: added %s interface %s", (flags & (IFF_LOOPBACK | IFF_BROADCAST)) ? "broadcast" : "unicast", buf); + } +#ifdef ENABLE_SWITCH_LOG + buf[0] = '\0'; + inet_ntop(hostaddr->addr_tx.sin.sin_family, &hostaddr->addr_tx.sin.sin_addr.s_addr, buf, sizeof(buf)); + netswitch_log(" -> %s:%d\n", buf, ntohs(netswitch->port_out)); +#endif + } else { + goto fail; + } + + /* Add address to list. */ + *p = hostaddr; + return ret; + +fail: + if (hostaddr->socket_tx >= 0) + close(hostaddr->socket_tx); + free(hostaddr); + return 0; +} + +static void +net_switch_update_hostaddrs(net_switch_t *netswitch) +{ + unsigned int added = 0; +#ifdef _WIN32 + DWORD buf_size = 16 * sizeof(INTERFACE_INFO); + INTERFACE_INFO *buf; +retry: + buf = (INTERFACE_INFO *) malloc(buf_size); + DWORD returned; + if (WSAIoctl(netswitch->socket_rx, SIO_GET_INTERFACE_LIST, NULL, 0, buf, buf_size, &returned, NULL, NULL) == SOCKET_ERROR) { + free(buf); + if (WSAGetLastError() == WSAEFAULT) { + buf_size *= 2; + goto retry; + } + } else { + returned /= sizeof(INTERFACE_INFO); + for (int i = 0; i < returned; i++) { + added += net_switch_add_hostaddr(netswitch, + (net_switch_sockaddr_t *) &buf[i].iiAddress.Address, + (net_switch_sockaddr_t *) &buf[i].iiBroadcastAddress.Address, + (net_switch_sockaddr_t *) &buf[i].iiNetmask.Address, + buf[i].iiFlags); + } + free(buf); + } +#else + struct ifaddrs *buf; + if (getifaddrs(&buf) >= 0) { + for (struct ifaddrs *addr = buf; addr; addr = addr->ifa_next) { + added += net_switch_add_hostaddr(netswitch, + (net_switch_sockaddr_t *) addr->ifa_addr, + (net_switch_sockaddr_t *) ((addr->ifa_flags & IFF_POINTOPOINT) ? addr->ifa_dstaddr : addr->ifa_broadaddr), + (net_switch_sockaddr_t *) addr->ifa_netmask, + addr->ifa_flags); + } + freeifaddrs(buf); + } +#endif + + /* Add loopback if it's not present. */ + struct sockaddr_in fallback = { + .sin_family = AF_INET, + .sin_addr = { .s_addr = htonl(INADDR_LOOPBACK) } + }; + struct sockaddr_in fallback_broadcast = { + .sin_family = AF_INET, + .sin_addr = { .s_addr = htonl(INADDR_BROADCAST) } + }; + added += net_switch_add_hostaddr(netswitch, + (net_switch_sockaddr_t *) (struct sockaddr *) &fallback, + (net_switch_sockaddr_t *) (struct sockaddr *) &fallback_broadcast, + NULL, IFF_UP | IFF_LOOPBACK); + + /* If no non-loopback interfaces have been successfully added, + fall back to IPv4 multicast on a single OS-selected interface. */ + if (!added) { + fallback.sin_addr.s_addr = htonl(INADDR_ANY); + net_switch_add_hostaddr(netswitch, + (net_switch_sockaddr_t *) (struct sockaddr *) &fallback, + (net_switch_sockaddr_t *) (struct sockaddr *) &fallback_broadcast, + NULL, IFF_UP | IFF_MULTICAST); + } +} + +static void +net_switch_thread(void *priv) +{ + net_switch_t *netswitch = (net_switch_t *) priv; + + /* Start polling. */ + netswitch_log("Network Switch: polling started\n"); + +#ifdef _WIN32 + WSAEventSelect(netswitch->socket_rx, netswitch->sock_event, FD_READ); + + HANDLE events[NET_EVENT_MAX]; + events[NET_EVENT_STOP] = net_event_get_handle(&netswitch->stop_event); + events[NET_EVENT_TX] = net_event_get_handle(&netswitch->tx_event); + events[NET_EVENT_RX] = netswitch->sock_event; +#else + struct pollfd pfd[NET_EVENT_MAX]; + pfd[NET_EVENT_STOP].fd = net_event_get_fd(&netswitch->stop_event); + pfd[NET_EVENT_STOP].events = POLLIN | POLLPRI; + + pfd[NET_EVENT_TX].fd = net_event_get_fd(&netswitch->tx_event); + pfd[NET_EVENT_TX].events = POLLIN | POLLPRI; + + pfd[NET_EVENT_RX].fd = netswitch->socket_rx; + pfd[NET_EVENT_RX].events = POLLIN | POLLPRI; +#endif + + int packets; + ssize_t len; +#ifdef _WIN32 + uint8_t run = 1; + while (run) { + int ret = WaitForMultipleObjects(NET_EVENT_MAX, events, FALSE, INFINITE); + switch (ret - WAIT_OBJECT_0) { + case NET_EVENT_STOP: + run = 0; +#else + while (1) { + poll(pfd, NET_EVENT_MAX, -1); + if (pfd[NET_EVENT_STOP].revents & POLLIN) { +#endif + net_event_clear(&netswitch->stop_event); + break; +#ifdef _WIN32 + + case NET_EVENT_TX: +#else + } + if (pfd[NET_EVENT_TX].revents & POLLIN) { +#endif + net_event_clear(&netswitch->tx_event); + netswitch->during_tx = 1; + packets = network_tx_popv(netswitch->card, netswitch->pkt_tx_v, SWITCH_PKT_BATCH); + for (int i = 0; i < packets; i++) { +#define MAC_FORMAT "(%02X:%02X:%02X:%02X:%02X:%02X -> %02X:%02X:%02X:%02X:%02X:%02X)" +#define MAC_FORMAT_ARGS(p) (p)[6], (p)[7], (p)[8], (p)[9], (p)[10], (p)[11], (p)[0], (p)[1], (p)[2], (p)[3], (p)[4], (p)[5] + netswitch_log("Network Switch: sending %d-byte packet " MAC_FORMAT "\n", + netswitch->pkt_tx_v[i].len, MAC_FORMAT_ARGS(netswitch->pkt_tx_v[i].data)); + + /* Send through all known host interfaces. */ + for (net_switch_hostaddr_t *hostaddr = netswitch->hostaddrs; hostaddr; hostaddr = hostaddr->next) + sendto(hostaddr->socket_tx, + (char *) netswitch->pkt_tx_v[i].data, netswitch->pkt_tx_v[i].len, 0, + &hostaddr->addr_tx.sa, sizeof(hostaddr->addr_tx.sa)); + } + netswitch->during_tx = 0; + + if (netswitch->recv_on_tx) { + do { + packets = network_rx_on_tx_popv(netswitch->card, netswitch->pkt_tx_v, SWITCH_PKT_BATCH); + for (int i = 0; i < packets; i++) + network_rx_put_pkt(netswitch->card, &(netswitch->pkt_tx_v[i])); + } while (packets > 0); + netswitch->recv_on_tx = 0; + } +#ifdef _WIN32 + break; + + case NET_EVENT_RX: +#else + } + if (pfd[NET_EVENT_RX].revents & POLLIN) { +#endif + len = recv(netswitch->socket_rx, (char *) netswitch->pkt.data, NET_MAX_FRAME, 0); + if (len < 12) { + netswitch_log("Network Switch: recv error (%d)\n", len); + } else if ((AS_U64(netswitch->pkt.data[6]) & le64_to_cpu(0xffffffffffffULL)) == netswitch->mac_addr_u64) { + /* A packet we've sent has looped back, drop it. */ + } else if (netswitch->promisc || /* promiscuous mode? */ + (netswitch->pkt.data[0] & 1) || /* broadcast packet? */ + ((AS_U64(netswitch->pkt.data[0]) & le64_to_cpu(0xffffffffffffULL)) == netswitch->mac_addr_u64)) { /* packet for me? */ + netswitch_log("Network Switch: receiving %d-byte packet " MAC_FORMAT "\n", + len, MAC_FORMAT_ARGS(netswitch->pkt.data)); + netswitch->pkt.len = len; + if (netswitch->during_tx) { + network_rx_on_tx_put_pkt(netswitch->card, &netswitch->pkt); + netswitch->recv_on_tx = 1; + } else { + network_rx_put_pkt(netswitch->card, &netswitch->pkt); + } + } else { + netswitch_log("Network Switch: dropping %d-byte packet " MAC_FORMAT "\n", + len, MAC_FORMAT_ARGS(netswitch->pkt.data)); + } +#ifdef _WIN32 + break; +#endif + } + } + + netswitch_log("Network Switch: polling stopped\n"); +} + +static void net_switch_close(void *priv); + +void * +net_switch_init(const netcard_t *card, const uint8_t *mac_addr, void *priv, char *netdrv_errbuf) +{ + netcard_conf_t *netcard = (netcard_conf_t *) priv; + + netswitch_log("Network Switch: initializing with group %d...\n", netcard->switch_group); + + net_switch_t *netswitch = calloc(1, sizeof(net_switch_t)); + memcpy(netswitch->mac_addr, mac_addr, sizeof(netswitch->mac_addr)); + netswitch->card = (netcard_t *) card; + netswitch->promisc = !!netcard->promisc_mode; + + /* Initialize receive socket. */ + netswitch->socket_rx = socket(AF_INET, SOCK_DGRAM, 0); + if (netswitch->socket_rx < 0) { + strncpy(netdrv_errbuf, "Could not initialize receive socket\n", NET_DRV_ERRBUF_SIZE); + goto fail; + } + + int val = 1; + if (setsockopt(netswitch->socket_rx, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof(val)) < 0) { + strncpy(netdrv_errbuf, "Could not set SO_REUSEADDR\n", NET_DRV_ERRBUF_SIZE); + goto fail; + } +#ifndef _WIN32 + if (setsockopt(netswitch->socket_rx, SOL_SOCKET, SO_REUSEPORT, (char *) &val, sizeof(val)) < 0) { + strncpy(netdrv_errbuf, "Could not set SO_REUSEPORT\n", NET_DRV_ERRBUF_SIZE); + goto fail; + } +#endif + + /* Disable multicast loopback on Windows. (no harm on other platforms) */ + val = 0; + setsockopt(netswitch->socket_rx, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &val, sizeof(val)); + + netswitch->port_out = htons(SWITCH_MULTICAST_PORT - NET_SWITCH_GRP_MIN + netcard->switch_group); + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_addr = { .s_addr = htonl(INADDR_ANY) }, + .sin_port = netswitch->port_out + }; + if (bind(netswitch->socket_rx, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + snprintf(netdrv_errbuf, NET_DRV_ERRBUF_SIZE, "Could not bind to port %d\n", (int) addr.sin_port); + goto fail; + } + + /* Add host interfaces. */ + net_switch_update_hostaddrs(netswitch); + if (!netswitch->hostaddrs) { + strncpy(netdrv_errbuf, "Could not add any interfaces\n", NET_DRV_ERRBUF_SIZE); + goto fail; + } + + for (int i = 0; i < SWITCH_PKT_BATCH; i++) + netswitch->pkt_tx_v[i].data = calloc(1, NET_MAX_FRAME); + netswitch->pkt.data = calloc(1, NET_MAX_FRAME); + net_event_init(&netswitch->tx_event); + net_event_init(&netswitch->stop_event); +#ifdef _WIN32 + netswitch->sock_event = CreateEvent(NULL, FALSE, FALSE, NULL); +#endif + + netswitch_log("Network Switch: creating thread...\n"); + netswitch->poll_tid = thread_create(net_switch_thread, netswitch); + + return netswitch; + +fail: + net_switch_close(netswitch); + return NULL; +} + +void +net_switch_close(void *priv) +{ + if (!priv) + return; + + net_switch_t *netswitch = (net_switch_t *) priv; + + netswitch_log("Network Switch: closing\n"); + + if (netswitch->poll_tid) { + /* Tell the polling thread to shut down. */ + net_event_set(&netswitch->stop_event); + + /* Wait for the thread to finish. */ + netswitch_log("Network Switch: waiting for thread to end...\n"); + thread_wait(netswitch->poll_tid); + } + + net_switch_hostaddr_t *hostaddr = netswitch->hostaddrs; + while (hostaddr) { + if (hostaddr->socket_tx >= 0) + close(hostaddr->socket_tx); + net_switch_hostaddr_t *next = hostaddr->next; + free(hostaddr); + hostaddr = next; + } + if (netswitch->socket_rx >= 0) + close(netswitch->socket_rx); + net_event_close(&netswitch->stop_event); + net_event_close(&netswitch->tx_event); + for (int i = 0; i < SWITCH_PKT_BATCH; i++) + free(netswitch->pkt_tx_v[i].data); + free(netswitch->pkt.data); + free(netswitch); +} + +const netdrv_t net_switch_drv = { + .notify_in = &net_switch_in_available, + .init = &net_switch_init, + .close = &net_switch_close, + .priv = NULL +}; diff --git a/src/network/net_tulip.c b/src/network/net_tulip.c index f93ac87670e..298cda23292 100644 --- a/src/network/net_tulip.c +++ b/src/network/net_tulip.c @@ -291,8 +291,6 @@ #define ETH_ALEN 6 -static bar_t tulip_pci_bar[3]; - struct tulip_descriptor { uint32_t status; uint32_t control; @@ -338,6 +336,8 @@ struct TULIPState { uint32_t bios_addr; uint8_t filter[16][6]; int has_bios; + + bar_t tulip_pci_bar[3]; }; typedef struct TULIPState TULIPState; @@ -346,10 +346,10 @@ static void tulip_desc_read(TULIPState *s, uint32_t p, struct tulip_descriptor *desc) { - dma_bm_read(p , (uint8_t *) &(desc->status) , 4, 4); - dma_bm_read(p + 4, (uint8_t *) &(desc->control) , 4, 4); - dma_bm_read(p + 8, (uint8_t *) &(desc->buf_addr1), 4, 4); - dma_bm_read(p + 12, (uint8_t *) &(desc->buf_addr2), 4, 4); + desc->status = mem_readl_phys(p); + desc->control = mem_readl_phys(p + 4); + desc->buf_addr1 = mem_readl_phys(p + 8); + desc->buf_addr2 = mem_readl_phys(p + 12); if (s->csr[0] & CSR0_DBO) { bswap32s(&desc->status); @@ -364,20 +364,15 @@ tulip_desc_write(TULIPState *s, uint32_t p, struct tulip_descriptor *desc) { if (s->csr[0] & CSR0_DBO) { - uint32_t status = bswap32(desc->status); - uint32_t control = bswap32(desc->control); - uint32_t buf_addr1 = bswap32(desc->buf_addr1); - uint32_t buf_addr2 = bswap32(desc->buf_addr2); - - dma_bm_write(p , (uint8_t *) &status , 4, 4); - dma_bm_write(p + 4, (uint8_t *) &control , 4, 4); - dma_bm_write(p + 8, (uint8_t *) &buf_addr1, 4, 4); - dma_bm_write(p + 12, (uint8_t *) &buf_addr2, 4, 4); + mem_writel_phys(p, bswap32(desc->status)); + mem_writel_phys(p + 4, bswap32(desc->control)); + mem_writel_phys(p + 8, bswap32(desc->buf_addr1)); + mem_writel_phys(p + 12, bswap32(desc->buf_addr2)); } else { - dma_bm_write(p , (uint8_t *) &(desc->status) , 4, 4); - dma_bm_write(p + 4, (uint8_t *) &(desc->control) , 4, 4); - dma_bm_write(p + 8, (uint8_t *) &(desc->buf_addr1), 4, 4); - dma_bm_write(p + 12, (uint8_t *) &(desc->buf_addr2), 4, 4); + mem_writel_phys(p, desc->status); + mem_writel_phys(p + 4, desc->control); + mem_writel_phys(p + 8, desc->buf_addr1); + mem_writel_phys(p + 12, desc->buf_addr2); } } @@ -438,10 +433,6 @@ tulip_copy_rx_bytes(TULIPState *s, struct tulip_descriptor *desc) len = s->rx_frame_len; } - if (s->rx_frame_len + len > sizeof(s->rx_frame)) { - return; - } - dma_bm_write(desc->buf_addr1, s->rx_frame + (s->rx_frame_size - s->rx_frame_len), len, 4); s->rx_frame_len -= len; } @@ -453,10 +444,6 @@ tulip_copy_rx_bytes(TULIPState *s, struct tulip_descriptor *desc) len = s->rx_frame_len; } - if (s->rx_frame_len + len > sizeof(s->rx_frame)) { - return; - } - dma_bm_write(desc->buf_addr2, s->rx_frame + (s->rx_frame_size - s->rx_frame_len), len, 4); s->rx_frame_len -= len; } @@ -581,7 +568,7 @@ static const uint16_t tulip_mdi_default[] = { 0x0600, 0x0001, 0x0000, - 0x3b40, + 0x0000, 0x0000, 0x0000, 0x0000, @@ -1241,34 +1228,34 @@ tulip_pci_read(UNUSED(int func), int addr, void *priv) ret = 0x02; break; case 0x10: - ret = (tulip_pci_bar[0].addr_regs[0] & 0x80) | 0x01; + ret = (s->tulip_pci_bar[0].addr_regs[0] & 0x80) | 0x01; break; case 0x11: - ret = tulip_pci_bar[0].addr_regs[1]; + ret = s->tulip_pci_bar[0].addr_regs[1]; break; case 0x12: - ret = tulip_pci_bar[0].addr_regs[2]; + ret = s->tulip_pci_bar[0].addr_regs[2]; break; case 0x13: - ret = tulip_pci_bar[0].addr_regs[3]; + ret = s->tulip_pci_bar[0].addr_regs[3]; break; #ifdef USE_128_BYTE_BAR case 0x14: - ret = (tulip_pci_bar[1].addr_regs[0] & 0x80); + ret = (s->tulip_pci_bar[1].addr_regs[0] & 0x80); break; #endif case 0x15: #ifdef USE_128_BYTE_BAR - ret = tulip_pci_bar[1].addr_regs[1]; + ret = s->tulip_pci_bar[1].addr_regs[1]; #else - ret = tulip_pci_bar[1].addr_regs[1] & 0xf0; + ret = s->tulip_pci_bar[1].addr_regs[1] & 0xf0; #endif break; case 0x16: - ret = tulip_pci_bar[1].addr_regs[2]; + ret = s->tulip_pci_bar[1].addr_regs[2]; break; case 0x17: - ret = tulip_pci_bar[1].addr_regs[3]; + ret = s->tulip_pci_bar[1].addr_regs[3]; break; case 0x2C: ret = s->subsys_ven_id & 0xFF; @@ -1283,16 +1270,16 @@ tulip_pci_read(UNUSED(int func), int addr, void *priv) ret = s->subsys_id >> 8; break; case 0x30: - ret = (tulip_pci_bar[2].addr_regs[0] & 0x01); + ret = (s->tulip_pci_bar[2].addr_regs[0] & 0x01); break; case 0x31: - ret = tulip_pci_bar[2].addr_regs[1]; + ret = s->tulip_pci_bar[2].addr_regs[1]; break; case 0x32: - ret = tulip_pci_bar[2].addr_regs[2]; + ret = s->tulip_pci_bar[2].addr_regs[2]; break; case 0x33: - ret = tulip_pci_bar[2].addr_regs[3]; + ret = s->tulip_pci_bar[2].addr_regs[3]; break; case 0x3C: ret = s->pci_conf[0x3C]; @@ -1346,9 +1333,9 @@ tulip_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv) tulip_readb_io, tulip_readw_io, tulip_readl_io, tulip_writeb_io, tulip_writew_io, tulip_writel_io, priv); - tulip_pci_bar[0].addr_regs[addr & 3] = val; - tulip_pci_bar[0].addr &= 0xffffff80; - s->PCIBase = tulip_pci_bar[0].addr; + s->tulip_pci_bar[0].addr_regs[addr & 3] = val; + s->tulip_pci_bar[0].addr &= 0xffffff80; + s->PCIBase = s->tulip_pci_bar[0].addr; if (s->pci_conf[0x4] & PCI_COMMAND_IO) { //pclog("PCI write=%02x, base=%04x, io?=%x.\n", addr, s->PCIBase, s->pci_conf[0x4] & PCI_COMMAND_IO); if (s->PCIBase != 0) @@ -1365,13 +1352,13 @@ tulip_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv) case 0x16: case 0x17: mem_mapping_disable(&s->memory); - tulip_pci_bar[1].addr_regs[addr & 3] = val; + s->tulip_pci_bar[1].addr_regs[addr & 3] = val; #ifdef USE_128_BYTE_BAR - tulip_pci_bar[1].addr &= 0xffffff80; + s->tulip_pci_bar[1].addr &= 0xffffff80; #else - tulip_pci_bar[1].addr &= 0xfffff000; + s->tulip_pci_bar[1].addr &= 0xfffff000; #endif - s->MMIOBase = tulip_pci_bar[1].addr; + s->MMIOBase = s->tulip_pci_bar[1].addr; if (s->pci_conf[0x4] & PCI_COMMAND_MEM) { //pclog("PCI write=%02x, mmiobase=%08x, mmio?=%x.\n", addr, s->PCIBase, s->pci_conf[0x4] & PCI_COMMAND_MEM); if (s->MMIOBase != 0) @@ -1390,10 +1377,10 @@ tulip_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv) return; mem_mapping_disable(&s->bios_rom.mapping); - tulip_pci_bar[2].addr_regs[addr & 3] = val; - tulip_pci_bar[2].addr &= 0xffff0001; - s->bios_addr = tulip_pci_bar[2].addr & 0xffff0000; - if (tulip_pci_bar[2].addr_regs[0] & 0x01) { + s->tulip_pci_bar[2].addr_regs[addr & 3] = val; + s->tulip_pci_bar[2].addr &= 0xffff0001; + s->bios_addr = s->tulip_pci_bar[2].addr & 0xffff0000; + if (s->tulip_pci_bar[2].addr_regs[0] & 0x01) { if (s->bios_addr != 0) mem_mapping_set_addr(&s->bios_rom.mapping, s->bios_addr, 0x10000); } @@ -1665,16 +1652,16 @@ nic_init(const device_t *info) } } - tulip_pci_bar[0].addr_regs[0] = 1; - tulip_pci_bar[1].addr_regs[0] = 0; - s->pci_conf[0x04] = 7; + s->tulip_pci_bar[0].addr_regs[0] = 1; + s->tulip_pci_bar[1].addr_regs[0] = 0; + s->pci_conf[0x04] = 7; /* Enable our BIOS space in PCI, if needed. */ if (s->has_bios) { rom_init(&s->bios_rom, ROM_PATH_DEC21140, s->bios_addr, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); - tulip_pci_bar[2].addr = 0xffff0000; + s->tulip_pci_bar[2].addr = 0xffff0000; } else - tulip_pci_bar[2].addr = 0; + s->tulip_pci_bar[2].addr = 0; mem_mapping_disable(&s->bios_rom.mapping); eeprom_data = (info->local == 3) ? s->eeprom_data : (uint8_t *) &nmc93cxx_eeprom_data(s->eeprom)[0]; diff --git a/src/network/netswitch.c b/src/network/netswitch.c deleted file mode 100644 index 1ec2c5e6f7b..00000000000 --- a/src/network/netswitch.c +++ /dev/null @@ -1,970 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Network Switch backend - * - * Authors: cold-brewed - * - * Copyright 2024 cold-brewed - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef _WIN32 -# define WIN32_LEAN_AND_MEAN -# include -# include -#else -# include -# include -#endif - -#define HAVE_STDARG_H -#include <86box/86box.h> -#include <86box/device.h> -#include <86box/thread.h> -#include <86box/timer.h> -#include <86box/network.h> -#include <86box/net_event.h> -#include <86box/random.h> -#include -#include "netswitch.h" -#include "pb_encode.h" -#include "pb_decode.h" - -#include "networkmessage.pb.h" - -bool ns_socket_setup(NSCONN *conn) { - - if(conn == NULL) { - errno=EINVAL; - return false; - } - -#ifdef _WIN32 - // Initialize Windows Socket API with the given version. - WSADATA wsaData; - if (WSAStartup(MAKEWORD(2, 0), &wsaData)) { - perror("WSAStartup"); - return false; - } -#endif - - /* Create the "main" socket - * Local mode: the listener socket for multicast packets - * Remote mode: the "main" socket for send and receive */ - conn->fddata = socket(AF_INET, SOCK_DGRAM, 0); - if (conn->fddata < 0) { - perror("socket"); - return false; - } - - /* Here things diverge depending on local or remote type */ - if(conn->switch_type == SWITCH_TYPE_LOCAL) { - - /* Set socket options - allow multiple sockets to use the same address */ - u_int on = 1; - if (setsockopt(conn->fddata, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0) { - perror("Reusing ADDR failed"); - return false; - } -#ifndef _WIN32 - /* ... and same port number - * Not needed on windows because SO_REUSEPORT doesn't exist there. However, the same - * functionality comes along with SO_REUSEADDR. */ - if (setsockopt(conn->fddata, SOL_SOCKET, SO_REUSEPORT, (char *) &on, sizeof(on)) < 0) { - perror("Reusing PORT failed"); - return false; - } -#endif - - memset(&conn->addr, 0, sizeof(conn->addr)); - conn->addr.sin_family = AF_INET; - conn->addr.sin_addr.s_addr = htonl(INADDR_ANY); - conn->addr.sin_port = htons(conn->local_multicast_port); - - /* Bind to receive address */ - if (bind(conn->fddata, (struct sockaddr *) &conn->addr, sizeof(conn->addr)) < 0) { - perror("bind"); - return false; - } - - /* Request to join multicast group */ - /*** NOTE: intermittent airplane (non-connected wifi) failures with 239.255.86.86 - needs more investigation */ - struct ip_mreq mreq; - mreq.imr_multiaddr.s_addr = inet_addr(conn->mcast_group); - mreq.imr_interface.s_addr = htonl(INADDR_ANY); - if (setsockopt(conn->fddata, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq)) < 0) { - perror("setsockopt"); - return false; - } - - /* Now create the outgoing data socket */ - conn->fdout = socket(AF_INET, SOCK_DGRAM, 0); - if (conn->fdout < 0) { - perror("out socket"); - return false; - } - - /* Set up destination address */ - memset(&conn->outaddr, 0, sizeof(conn->outaddr)); - conn->outaddr.sin_family = AF_INET; - conn->outaddr.sin_addr.s_addr = inet_addr(conn->mcast_group); - conn->outaddr.sin_port = htons(conn->local_multicast_port); - } else if (conn->switch_type == SWITCH_TYPE_REMOTE) { - /* Remote switch path */ - int status; - struct addrinfo hints; - struct addrinfo *servinfo; - char connect_ip[128] = "\0"; - - memset(&hints, 0, sizeof hints); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = AI_PASSIVE; // not sure? - - if((status = getaddrinfo(conn->nrs_hostname, NULL, &hints, &servinfo)) != 0) { - net_switch_log("getaddrinfo error: %s\n", gai_strerror(status)); - errno=EFAULT; - return false; - } - - for(const struct addrinfo *p = servinfo; p != NULL; p = p->ai_next) { // NOLINT (only want the first result) - /* Take the first result, ipv4 since AF_INET was set in the hints */ - const struct sockaddr_in *ipv4 = (struct sockaddr_in *) p->ai_addr; - const void *addr = &(ipv4->sin_addr); - inet_ntop(p->ai_family, addr, connect_ip, sizeof connect_ip); - break; - } - freeaddrinfo(servinfo); - - if(strlen(connect_ip) == 0) { - /* Couldn't look up the hostname */ - net_switch_log("Hostname lookup failure?\n"); - errno=EFAULT; - return false; - } - - /* Set up local socket address and port */ - memset(&conn->addr, 0, sizeof(conn->addr)); - conn->addr.sin_family = AF_INET; - conn->addr.sin_addr.s_addr = htonl(INADDR_ANY); - conn->addr.sin_port = htons(conn->remote_source_port); - - /* Bind to receive address. Try the first 100 ports to allow the use of multiple systems simultaneously */ - for(int i=0; i<100; i++) { - if(i==99) { - net_switch_log("Unable to find an available port to bind\n"); - return false; - } - if (bind(conn->fddata, (struct sockaddr *) &conn->addr, sizeof(conn->addr)) < 0) { - net_switch_log("local port %d unavailable, trying next..\n", conn->remote_source_port); - conn->remote_source_port += 1; - conn->addr.sin_port = htons(conn->remote_source_port); - continue ; - } else { - net_switch_log("** Local port for net remote switch is %d\n", conn->remote_source_port); - break; - } - - } - - - /* Set up remote address and port */ - memset(&conn->outaddr, 0, sizeof(conn->outaddr)); - conn->outaddr.sin_family = AF_INET; - conn->outaddr.sin_addr.s_addr = inet_addr(connect_ip); - conn->outaddr.sin_port = htons(conn->remote_network_port); - - /* In remote mode the file descriptor for send (fdout) is the same as receive */ - conn->fdout = conn->fddata; - - } else { - errno=EINVAL; - return false; - } - - return true; -} - -NSCONN * -ns_open(struct ns_open_args *open_args) { - struct nsconn *conn=NULL; - - /* Each "group" is really just the base port + group number - * A different group effectively gets you a different switch - * Clamp the group at MAX_SWITCH_GROUP */ - if(open_args->group > MAX_SWITCH_GROUP) { - open_args->group = MAX_SWITCH_GROUP; - } - // FIXME: hardcoded for testing - char *mcast_group = "239.255.86.86"; // Admin scope - // char *mcast_group = "224.0.0.86"; // Local scope - - if ( (conn=calloc(1,sizeof(struct nsconn)))==NULL) { - errno=ENOMEM; - return NULL; - } - - /* Type */ - conn->switch_type = open_args->type; - - /* Allocate the fragment buffer */ - for (int i = 0; i < FRAGMENT_BUFFER_LENGTH; i++) { - conn->fragment_buffer[i] = calloc(1, sizeof(ns_fragment_t)); - /* Set the default size to 0 and null data buffer to indicate it is unused. - * The data buffer will be allocated as needed. */ - conn->fragment_buffer[i]->size = 0; - conn->fragment_buffer[i]->data = NULL; - } -// net_switch_log("Fragment buffers: %d total, %d each\n", FRAGMENT_BUFFER_LENGTH, MAX_FRAME_SEND_SIZE); - - snprintf(conn->mcast_group, MAX_MCAST_GROUP_LEN, "%s", mcast_group); - conn->flags = open_args->flags; - - /* Increment the multicast port by the switch group number. Each group is - * just a different port. */ - conn->local_multicast_port = open_args->group + NET_SWITCH_MULTICAST_PORT; - conn->remote_network_port = NET_SWITCH_REMOTE_PORT; - /* Source ports for remote switch will start here and be incremented until an available port is found */ - conn->remote_source_port = NET_SWITCH_REMOTE_PORT + NET_SWITCH_RECV_PORT_OFFSET; - - /* Remote switch hostname */ - strncpy(conn->nrs_hostname, open_args->nrs_hostname, sizeof(conn->nrs_hostname) - 1); - conn->nrs_hostname[127] = 0x00; - - /* Switch type */ - if(conn->switch_type == SWITCH_TYPE_REMOTE) { - net_switch_log("Connecting to remote %s:%d, initial local port %d, group %d\n", conn->nrs_hostname, conn->remote_network_port, conn->remote_source_port, open_args->group); - } else { - net_switch_log("Opening IP %s, port %d, group %d\n", mcast_group, conn->local_multicast_port, open_args->group); - } - - /* Client state, disconnected by default. - * Primarily used in remote mode */ - conn->client_state = DISCONNECTED; - - /* Client ID. Generate the ID if set to zero. */ - if(open_args->client_id == 0) { - conn->client_id = ns_gen_client_id(); - } - - /* MAC address is set from the emulated card */ - memcpy(conn->mac_addr, open_args->mac_addr, PB_MAC_ADDR_SIZE); - - /* Protocol version */ - conn->version = NS_PROTOCOL_VERSION; - - if(!ns_socket_setup(conn)) { - goto fail; - } - - if (conn->switch_type == SWITCH_TYPE_REMOTE) { - /* Perhaps one day do the entire handshake process here */ - if(!ns_send_control(conn, MessageType_MESSAGE_TYPE_CONNECT_REQUEST)) { - goto fail; - } - conn->client_state = CONNECTING; - net_switch_log("Client state is now CONNECTING\n"); - } else { - conn->client_state = LOCAL; - } - - /* Initialize sequence numbers */ - conn->sequence = 1; - conn->remote_sequence = 1; - - /* Initialize stats */ - conn->stats.max_tx_frame = 0; - conn->stats.max_tx_packet = 0; - conn->stats.max_rx_frame = 0; - conn->stats.max_rx_packet = 0; - conn->stats.total_rx_packets = 0; - conn->stats.total_tx_packets = 0; - conn->stats.total_fragments = 0; - conn->stats.max_vec = 0; - memcpy(conn->stats.last_tx_ethertype, (uint8_t []) { 0, 0}, sizeof(conn->stats.last_tx_ethertype)); - memcpy(conn->stats.last_rx_ethertype, (uint8_t []) { 0, 0}, sizeof(conn->stats.last_rx_ethertype)); - - /* Assuming all went well we have our sockets */ - return conn; - - /* Cleanup */ -fail: - for (int i = 0; i < FRAGMENT_BUFFER_LENGTH; i++) { - free(conn->fragment_buffer[i]); - } - return NULL; -} - -int -ns_pollfd(const NSCONN *conn) { - if (conn->fddata != 0) - return conn->fddata; - else { - errno=EBADF; - return -1; - } -} - -ssize_t -ns_sock_recv(const NSCONN *conn,void *buf, const size_t len, const int flags) { - if (fd_valid(conn->fddata)) - return recv(conn->fddata,buf,len,0); - else { - errno=EBADF; - return -1; - } -} - -ssize_t -ns_sock_send(NSCONN *conn,const void *buf, const size_t len, const int flags) { - if (fd_valid(conn->fddata)) { - /* Use the outgoing socket for sending, set elsewhere: - * Remote mode: same as sending - * Local mode: different from sending */ - return sendto(conn->fdout, buf, len, 0, (struct sockaddr *) &conn->outaddr, sizeof(conn->outaddr)); - } else { - errno=EBADF; - return -1; - } -} - -ssize_t -ns_send_pb(NSCONN *conn, const netpkt_t *packet,int flags) { - - NetworkMessage network_message = NetworkMessage_init_zero; - uint8_t fragment_count; - - /* Do we need to fragment? First, determine how many packets we will be sending */ - if(packet->len <= MAX_FRAME_SEND_SIZE) { - fragment_count = 1; -// net_switch_log("No Fragmentation. Frame size %d is less than max size %d\n", packet->len, MAX_FRAME_SEND_SIZE); - } else { - /* Since we're using integer math and the remainder is - * discarded we'll add one to the result *unless* the result can be evenly divided. */ - const uint8_t extra = (packet->len % MAX_FRAME_SEND_SIZE) == 0 ? 0 : 1; - fragment_count = (packet->len / MAX_FRAME_SEND_SIZE) + extra; -// net_switch_log("Fragmentation required, frame size %d exceeds max size %d\n", packet->len, MAX_FRAME_SEND_SIZE); - } - - /* Loop here for each fragment. Send each fragment. In the even that the packet is *not* a fragment (regular data packet) - * this will only execute once. */ - const uint32_t fragment_sequence = conn->sequence; - const int64_t packet_timestamp = ns_get_current_millis(); - for (uint8_t fragment_index = 0; fragment_index < fragment_count; fragment_index++) { - uint8_t buffer[NET_SWITCH_BUFFER_LENGTH]; - pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer)); -#ifdef ENABLE_NET_SWITCH_PB_FILE_DEBUG - uint8_t file_buffer[NET_SWITCH_BUFFER_LENGTH]; - /* file_stream used for debugging and writing the message to a file */ - pb_ostream_t file_stream = pb_ostream_from_buffer(file_buffer, sizeof(file_buffer)); -#endif - /* Single frame is type DATA, fragments are FRAGMENT */ - network_message.message_type = fragment_count > 1 ? MessageType_MESSAGE_TYPE_FRAGMENT : MessageType_MESSAGE_TYPE_DATA; - network_message.client_id = conn->client_id; - network_message.timestamp = packet_timestamp; - network_message.version = conn->version; - - /* Need some additional data if we're a fragment */ - if(fragment_count > 1) { - network_message.fragment.total = fragment_count; - network_message.fragment.id = fragment_sequence; - network_message.fragment.sequence = fragment_index + 1; - network_message.has_fragment = true; - } - - /* TODO: Better / real ack logic. Needs its own function. Currently just putting in dummy data. */ - network_message.ack.id = 1; - network_message.ack.history = 1; - network_message.has_ack = true; - network_message.sequence = conn->sequence; - - /* Frame data must be allocated */ - network_message.frame = calloc(1, PB_BYTES_ARRAY_T_ALLOCSIZE(packet->len)); - - /* Calculate offsets based on our position in the fragment. - * For anything other than the *last* packet, we'll have a max frame size */ - uint16_t copy_length; - const uint16_t copy_offset = fragment_index * MAX_FRAME_SEND_SIZE; - if(fragment_index == (fragment_count - 1)) { - copy_length = packet->len % MAX_FRAME_SEND_SIZE == 0 ? MAX_FRAME_SEND_SIZE : packet->len % MAX_FRAME_SEND_SIZE; - } else { - copy_length = MAX_FRAME_SEND_SIZE; - } - if(fragment_count > 1) { -// net_switch_log("Fragment %d/%d, %d bytes\n", fragment_index + 1, fragment_count, copy_length); - } - network_message.frame->size = copy_length; - memcpy(network_message.frame->bytes, packet->data + copy_offset, copy_length); - - /* mac address must be allocated */ - network_message.mac = calloc(1, PB_BYTES_ARRAY_T_ALLOCSIZE(PB_MAC_ADDR_SIZE)); - network_message.mac->size = PB_MAC_ADDR_SIZE; - memcpy(network_message.mac->bytes, conn->mac_addr, PB_MAC_ADDR_SIZE); - - /* Encode the protobuf message */ - if (!pb_encode_ex(&stream, NetworkMessage_fields, &network_message,PB_ENCODE_DELIMITED)) { - net_switch_log("Encoding failed: %s\n", PB_GET_ERROR(&stream)); - errno = EBADF; - return -1; - } - - /* Send on the socket */ - const ssize_t nc = ns_sock_send(conn, buffer, stream.bytes_written, 0); - if(!nc) { - net_switch_log("Error sending data on the socket\n"); - errno=EBADF; - pb_release(NetworkMessage_fields, &network_message); - return -1; - } -#ifdef ENABLE_NET_SWITCH_PB_FILE_DEBUG - /* File writing for troubleshooting when needed */ - FILE *f = fopen("/var/tmp/pbuf", "wb"); - if (f) { - if (!pb_encode(&file_stream, NetworkMessage_fields, &network_message)) { - net_switch_log("File encoding failed: %s\n", PB_GET_ERROR(&file_stream)); - } - fwrite(file_buffer, file_stream.bytes_written, 1, f); - fclose(f); - } else { - net_switch_log("file open failed\n"); - } -#endif - - /* Stats */ - if(network_message.frame->size > conn->stats.max_tx_frame) { - conn->stats.max_tx_frame = network_message.frame->size; - } - if(nc > conn->stats.max_tx_packet) { - conn->stats.max_tx_packet = nc; - } - if(nc > MAX_FRAME_SEND_SIZE) { - conn->stats.total_fragments = fragment_count > 1 ? conn->stats.total_fragments + fragment_count : conn->stats.total_fragments; - } - conn->stats.total_tx_packets++; - memcpy(conn->stats.last_tx_ethertype, &packet->data[12], 2); - - /* Increment the sequence number */ - seq_increment(conn); - - /* nanopb will free all the allocated entries for us */ - pb_release(NetworkMessage_fields, &network_message); - - } - - return packet->len; -} - -bool store_fragment(const NSCONN *conn, const NetworkMessage *network_message) { - - if(conn == NULL || network_message == NULL) { - return false; - } - - /* The fragment sequence indicates which fragment this is in the overall fragment - * collection. This is used to index the fragments while being stored for reassembly - * (zero indexed locally) */ - const uint32_t fragment_index = network_message->fragment.sequence - 1; - const uint32_t fragment_size = network_message->frame->size; - - /* Make sure the fragments aren't too small - * (see header notes about size requirements for MIN_FRAG_RECV_SIZE and FRAGMENT_BUFFER_LENGTH) - * NOTE: The last packet is exempt from this rule because it can have a smaller amount. - * This is primarily to ensure there's enough space to fit all the fragments. */ - if(network_message->fragment.sequence != network_message->fragment.total) { - if (network_message->frame->size < MIN_FRAG_RECV_SIZE) { - net_switch_log("size: %d < %d\n", network_message->frame->size, MIN_FRAG_RECV_SIZE); - return false; - } - } - - /* Make sure we can handle the amount of incoming fragments */ - if (network_message->fragment.total > FRAGMENT_BUFFER_LENGTH) { - net_switch_log("buflen: %d > %d\n", network_message->fragment.total, FRAGMENT_BUFFER_LENGTH); - return false; - } - - /* Allocate or reallocate as needed. - * size > 0 indicates this buffer has already been allocated. */ - if(conn->fragment_buffer[fragment_index]->size > 0) { - conn->fragment_buffer[fragment_index]->data = realloc(conn->fragment_buffer[fragment_index]->data, sizeof(char) * fragment_size); - } else { - conn->fragment_buffer[fragment_index]->data = calloc(1, sizeof(char) * fragment_size); - } - - if (conn->fragment_buffer[fragment_index]->data == NULL) { - net_switch_log("Failed to allocate / reallocate fragment buffer space\n"); - return false; - } - - /* Each fragment will belong to a particular ID. All members will have the same ID, - * which is generally set to the sequence number of the first fragment */ - conn->fragment_buffer[fragment_index]->id = network_message->fragment.id; - /* The sequence here is set to the index of the packet in the total fragment collection - * (network_message->fragment.sequence) */ - conn->fragment_buffer[fragment_index]->sequence = fragment_index; - /* Total number of fragments in this set */ - conn->fragment_buffer[fragment_index]->total = network_message->fragment.total; - /* The sequence number from the packet that contained the fragment */ - conn->fragment_buffer[fragment_index]->packet_sequence = network_message->sequence; - /* Copy the fragment data and size */ - /* The size of fragment_buffer[fragment_index]->data is checked against MAX_FRAME_SEND_SIZE above */ - memcpy(conn->fragment_buffer[fragment_index]->data, network_message->frame->bytes, fragment_size); - conn->fragment_buffer[fragment_index]->size = fragment_size; - /* 10 seconds for a TTL */ - conn->fragment_buffer[fragment_index]->ttl = ns_get_current_millis() + 10000; - - return true; -} - -bool -reassemble_fragment(const NSCONN *conn, netpkt_t *pkt, const uint32_t packet_count) -{ - uint32_t total = 0; - - /* Make sure the reassembled packet doesn't exceed NET_MAX_FRAME */ -// if (packet_count * MAX_FRAME_SEND_SIZE > NET_MAX_FRAME) { -// return false; -// } - - /* Too many packets! */ - if (packet_count > FRAGMENT_BUFFER_LENGTH) { - return false; - } - - // TODO: Check fragment ID - // TODO: Check TTL - - /* Get the fragment size from the first entry. All fragments in a particular - * set must be of the same size except the last fragment, which may be smaller. - * The fragment size will be used to determine the offset. */ - const uint16_t fragment_size = conn->fragment_buffer[0]->size; - -// net_switch_log("Reassembling %d fragments\n", packet_count); - - for(int i = 0; i < packet_count; i++) { - /* Size of zero means we're trying to assemble from a bad fragment */ - if(conn->fragment_buffer[i]->size == 0) { - net_switch_log("Fragment size 0 when trying to reassemble (id %i/index %i/seq %i/ total %i)\n",conn->fragment_buffer[i]->id, i, conn->fragment_buffer[i]->sequence, conn->fragment_buffer[i]->total); - return false; - } - if(conn->fragment_buffer[i]->data == NULL) { - net_switch_log("Missing fragment data when trying to reassemble\n"); - return false; - } - - memcpy(pkt->data + (fragment_size * i), conn->fragment_buffer[i]->data, conn->fragment_buffer[i]->size); - total += conn->fragment_buffer[i]->size; - - /* Zero out the size to indicate the slot is unused */ - conn->fragment_buffer[i]->size = 0; - free(conn->fragment_buffer[i]->data); - conn->fragment_buffer[i]->data = NULL; - } - - /* Set the size, must cast due to netpkt_t (len is int) */ - pkt->len = (int) total; -// net_switch_log("%d bytes reassembled and converted to data packet.\n", pkt->len); - - return true; -} - -bool -ns_recv_pb(NSCONN *conn, ns_rx_packet_t *packet,size_t len,int flags) { - NetworkMessage network_message = NetworkMessage_init_zero; - ns_rx_packet_t *ns_packet = packet; - - uint8_t buffer[NET_SWITCH_BUFFER_LENGTH]; - - /* TODO: Use the passed len? Most likely not needed */ - const ssize_t nc = ns_sock_recv(conn, buffer, NET_SWITCH_BUFFER_LENGTH, 0); - if(!nc) { - net_switch_log("Error receiving data on the socket\n"); - errno=EBADF; - return false; - } - pb_istream_t stream = pb_istream_from_buffer(buffer, sizeof(buffer)); - - if (!pb_decode_delimited(&stream, NetworkMessage_fields, &network_message)) { - /* Decode failed */ - net_switch_log("PB decoding failed: %s\n", PB_GET_ERROR(&stream)); - /* Allocated fields are automatically released upon failure */ - return false; - } - - /* Basic checks for validity */ - if(network_message.mac == NULL || network_message.message_type == MessageType_MESSAGE_TYPE_UNSPECIFIED || - network_message.client_id == 0) { - net_switch_log("Invalid packet received! Skipping..\n"); - goto fail; - } - - /* These fields should always be set. Start copying into our packet structure. */ - ns_packet->client_id = network_message.client_id; - ns_packet->type = network_message.message_type; - memcpy(ns_packet->mac, network_message.mac->bytes, PB_MAC_ADDR_SIZE); - ns_packet->timestamp = network_message.timestamp; - ns_packet->version = network_message.version; - conn->remote_sequence = network_message.sequence; - conn->last_packet_stamp = network_message.timestamp; - - /* Control messages take a different path */ - if(network_message.message_type != MessageType_MESSAGE_TYPE_DATA && - network_message.message_type != MessageType_MESSAGE_TYPE_FRAGMENT) { - process_control_packet(conn, ns_packet); - pb_release(NetworkMessage_fields, &network_message); - return true; - } - - /* All packets should be DATA or FRAGMENT at this point and have a frame */ - if(network_message.frame == NULL) { - net_switch_log("Invalid data packet received! Frame is null. Skipping..\n"); - goto fail; - } - - /* Fragment path first */ - if(network_message.message_type == MessageType_MESSAGE_TYPE_FRAGMENT) { - - /* Store fragment */ - if(!store_fragment(conn, &network_message)) { - net_switch_log("Failed to store fragment\n"); - goto fail; - } - - /* Is this the last fragment? If not, return */ - if(network_message.fragment.sequence != network_message.fragment.total) { - // FIXME: Really dumb, needs to be smarter - pb_release(NetworkMessage_fields, &network_message); - return true; - } - - /* This is the last fragment. Attempt to reassemble */ - if(!reassemble_fragment(conn, &ns_packet->pkt, network_message.fragment.total)) { - net_switch_log("Failed to reassemble fragment\n"); - goto fail; - } - /* Change the type to DATA */ - ns_packet->type = MessageType_MESSAGE_TYPE_DATA; - - } else { - /* Standard DATA packet path. Copy frame from the message */ - memcpy(ns_packet->pkt.data, network_message.frame->bytes, network_message.frame->size); - ns_packet->pkt.len = network_message.frame->size; - } - - /* Stats */ - if(network_message.frame->size > conn->stats.max_rx_frame) { - conn->stats.max_rx_frame = network_message.frame->size; - } - if(nc > conn->stats.max_rx_packet) { - conn->stats.max_rx_packet = nc; - } - memcpy(conn->stats.last_rx_ethertype, &packet->pkt.data[12], 2); - conn->stats.total_rx_packets++; - /* End Stats */ - - /* nanopb allocates the necessary fields while serializing. - They need to be manually released once you are done with the message */ - pb_release(NetworkMessage_fields, &network_message); - return true; -fail: - pb_release(NetworkMessage_fields, &network_message); - return false; -} - -bool process_control_packet(NSCONN *conn, const ns_rx_packet_t *packet) { - - control_packet_info_t packet_info = get_control_packet_info(*packet, conn->mac_addr); -// net_switch_log("Last timestamp: %lld\n", ns_get_current_millis()); -// net_switch_log("(%lld ms) [%03d] ", ns_get_current_millis() - packet_info.timestamp, conn->sequence); - - /* I probably want to eventually differentiate between local and remote here, kind of basic now */ - if(!packet_info.is_packet_from_me) { /* in case of local mode */ - switch (packet_info.type) { - case MessageType_MESSAGE_TYPE_JOIN: - net_switch_log("Client ID 0x%08llx (MAC %s) has joined the chat\n", packet_info.client_id, packet_info.src_mac_h); - break; - case MessageType_MESSAGE_TYPE_LEAVE: - net_switch_log("Client ID 0x%08llx (MAC %s) has left us\n", packet_info.client_id, packet_info.src_mac_h); - break; - case MessageType_MESSAGE_TYPE_KEEPALIVE: -// net_switch_log("Client ID 0x%08llx (MAC %s) is still alive\n", packet_info.client_id, packet_info.src_mac_h); - break; - case MessageType_MESSAGE_TYPE_ACK: -// net_switch_log("Client ID 0x%08llx (MAC %s) has sent an ACK\n", packet_info.client_id, packet_info.src_mac_h); - break; - case MessageType_MESSAGE_TYPE_CONNECT_REPLY: - conn->client_state = CONNECTED; - net_switch_log("Client ID 0x%08llx (MAC %s) has sent a connection reply\n", packet_info.client_id, packet_info.src_mac_h); - net_switch_log("Client state is now CONNECTED\n"); - break; - case MessageType_MESSAGE_TYPE_FRAGMENT: - net_switch_log("Client ID 0x%08llx (MAC %s) has sent a fragment\n", packet_info.client_id, packet_info.src_mac_h); - break; - default: - net_switch_log("Client ID 0x%08llx (MAC %s) has sent a message that we don't understand (type %d)\n", packet_info.client_id, packet_info.src_mac_h, packet_info.type); - break; - } - } - return true; - -} - -bool -ns_send_control(NSCONN *conn, const MessageType type) { - - NetworkMessage network_message = NetworkMessage_init_zero; - uint8_t buffer[NET_SWITCH_BUFFER_LENGTH]; - - pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer)); - network_message.message_type = type; - network_message.client_id = conn->client_id; - - /* No frame data so we only need to allocate mac address */ - network_message.mac = calloc(1, PB_BYTES_ARRAY_T_ALLOCSIZE(PB_MAC_ADDR_SIZE)); - network_message.mac->size = PB_MAC_ADDR_SIZE; - memcpy(network_message.mac->bytes, conn->mac_addr, PB_MAC_ADDR_SIZE); - - network_message.timestamp = ns_get_current_millis(); - network_message.version = conn->version; - network_message.sequence = conn->sequence; - - if (!pb_encode_ex(&stream, NetworkMessage_fields, &network_message, PB_ENCODE_DELIMITED)) { - net_switch_log("Encoding failed: %s\n", PB_GET_ERROR(&stream)); - errno = EBADF; - return false; - } - - const ssize_t nc = ns_sock_send(conn, buffer, stream.bytes_written, 0); - if(!nc) { - net_switch_log("Error sending control message on the socket\n"); - errno=EBADF; - pb_release(NetworkMessage_fields, &network_message); - return -1; - } - /* Increment the sequence number */ - seq_increment(conn); - - /* Stats */ - conn->stats.total_tx_packets++; - - /* Must release allocated data */ - pb_release(NetworkMessage_fields, &network_message); - - return true; -} - -uint32_t -ns_gen_client_id(void) { - uint32_t msb; - do { - msb = random_generate(); - } while (msb < 0x10); - return ( random_generate() | (random_generate() << 8) | (random_generate() << 16) | (msb << 24)); -} - -const char * -ns_printable_message_type(const MessageType type) -{ - switch (type) { - case MessageType_MESSAGE_TYPE_DATA: - return "Data"; - case MessageType_MESSAGE_TYPE_JOIN: - return "Join"; - case MessageType_MESSAGE_TYPE_LEAVE: - return "Leave"; - case MessageType_MESSAGE_TYPE_KEEPALIVE: - return "Keepalive"; - case MessageType_MESSAGE_TYPE_FRAGMENT: - return "Fragment"; - case MessageType_MESSAGE_TYPE_ACK: - return "Ack"; - case MessageType_MESSAGE_TYPE_UNSPECIFIED: - return "Unspecified (shouldn't get this)"; - default: - return "Unknown message type - probably hasn't been added yet!"; - } -} - -int64_t -ns_get_current_millis(void) { - struct timeval time; - gettimeofday(&time, NULL); - /* Windows won't properly promote integers so this is necessary */ - const int64_t seconds = (int64_t) time.tv_sec * 1000; - - return seconds + (time.tv_usec / 1000); -} - -int -ns_flags(const NSCONN *conn) { - return conn->flags; -} - -int -ns_close(NSCONN *conn) { - if(conn->switch_type == SWITCH_TYPE_REMOTE) { - /* TBD */ - } - /* No need to check the return here as we're closing out */ - ns_send_control(conn, MessageType_MESSAGE_TYPE_LEAVE); - for (int i = 0; i < FRAGMENT_BUFFER_LENGTH; i++) { - if (conn->fragment_buffer[i]->size > 0) { - free(conn->fragment_buffer[i]->data); - conn->fragment_buffer[i]->data = NULL; - } - free(conn->fragment_buffer[i]); - } - close(conn->fddata); - close(conn->fdout); - return 0; -} - -bool is_control_packet(const ns_rx_packet_t *packet) { - return packet->type != MessageType_MESSAGE_TYPE_DATA; -} - -bool is_fragment_packet(const ns_rx_packet_t *packet) { - return packet->type == MessageType_MESSAGE_TYPE_FRAGMENT; -} - -bool ns_connected(const NSCONN *conn) { - if(conn->switch_type == SWITCH_TYPE_LOCAL) { - return true; - } - - if(conn->switch_type == SWITCH_TYPE_REMOTE) { - if(conn->client_state == CONNECTED) { - return true; - } - } - - return false; -} - -char* formatted_mac(uint8_t mac_addr[6]) -{ - char *mac_h = calloc(1, sizeof(char)* 32); - for(int i=0; i < 6; i++) { - char octet[4]; - snprintf(octet, sizeof(octet), "%02X%s", mac_addr[i], i < 5 ? ":" : ""); - strncat(mac_h, octet, sizeof(mac_h) - 1); - } - return mac_h; -} - -control_packet_info_t get_control_packet_info(const ns_rx_packet_t packet, const uint8_t *my_mac) -{ - control_packet_info_t packet_info; - - packet_info.src_mac_h[0] = '\0'; - packet_info.printable[0] = '\0'; - packet_info.client_id = packet.client_id; - memcpy(packet_info.src_mac, &packet.mac, 6); - packet_info.type = packet.type; - packet_info.is_packet_from_me = (memcmp(my_mac, packet_info.src_mac, sizeof(uint8_t) * 6) == 0); - char *formatted_mac_h = formatted_mac(packet_info.src_mac); - strncpy(packet_info.src_mac_h, formatted_mac_h, MAX_PRINTABLE_MAC); - free(formatted_mac_h); - snprintf(packet_info.printable, sizeof(packet_info.printable), "%s", ns_printable_message_type(packet_info.type)); - packet_info.timestamp = packet.timestamp; - - return packet_info; -} - -data_packet_info_t -get_data_packet_info(const netpkt_t *packet, const uint8_t *my_mac) { - data_packet_info_t packet_info; - - packet_info.src_mac_h[0] = '\0'; - packet_info.dest_mac_h[0] = '\0'; - packet_info.my_mac_h[0] = '\0'; - packet_info.printable[0] = '\0'; - - memcpy(packet_info.dest_mac,&packet->data[0], 6); - memcpy(packet_info.src_mac, &packet->data[6], 6); - - /* Broadcast and multicast are treated the same at L2 and both will have the - * least significant bit of 1 in the first transmitted byte. - * The below test matches 0xFF for standard broadcast along with 0x01 and 0x33 for multicast */ - packet_info.is_broadcast = ((packet->data[0] & 1) == 1); - packet_info.is_packet_for_me = (memcmp(my_mac, packet_info.dest_mac, sizeof(uint8_t) * 6) == 0); - packet_info.is_packet_from_me = (memcmp(my_mac, packet_info.src_mac, sizeof(uint8_t) * 6) == 0); - packet_info.is_data_packet = packet->len > 0; - packet_info.size = packet->len; - - /* Since this function is applied to every packet, only enable the pretty formatting below - * if logging is specifically enabled. */ -#ifdef ENABLE_NET_SWITCH_LOG - /* Pretty formatting for hardware addresses */ - for(int i=0; i < 6; i++) { - char octet[4]; - snprintf(octet, sizeof(octet), "%02X%s", packet_info.src_mac[i], i < 5 ? ":" : ""); - strncat(packet_info.src_mac_h, octet, sizeof (packet_info.src_mac_h) - 1); - - snprintf(octet, sizeof(octet), "%02X%s", packet_info.dest_mac[i], i < 5 ? ":" : ""); - strncat(packet_info.dest_mac_h, octet, sizeof (packet_info.dest_mac_h) - 1); - - snprintf(octet, sizeof(octet), "%02X%s", my_mac[i], i < 5 ? ":" : ""); - strncat(packet_info.my_mac_h, octet, sizeof (packet_info.my_mac_h) - 1); - } - - /* Printable output formatting */ - if(packet_info.is_broadcast) { - if(packet_info.is_packet_from_me) { - snprintf(packet_info.printable, sizeof(packet_info.printable), "(broadcast)"); - } else { - snprintf(packet_info.printable, sizeof(packet_info.printable), "%s (broadcast)", packet_info.src_mac_h); - } - } else { - snprintf(packet_info.printable, sizeof(packet_info.printable), "%s%s -> %s%s", packet_info.src_mac_h, packet_info.is_packet_from_me ? " (me)" : " ", - packet_info.dest_mac_h, packet_info.is_packet_for_me ? " (me)" : ""); - } -#endif - return packet_info; -} - -bool -fd_valid(const int fd) -{ -#ifdef _WIN32 - int error_code; - int error_code_size = sizeof(error_code); - getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *) &error_code, &error_code_size); - if (error_code == WSAENOTSOCK) { - return false; - } - return true; -#else - if (fcntl(fd, F_GETFD) == -1) { - return false; - } - /* All other values will be a valid fd */ - return true; -#endif -} - -bool -seq_increment(NSCONN *conn) -{ - if(conn == NULL) { - return false; - } - conn->sequence++; - if (conn->sequence == 0) { - conn->sequence = 1; - } - return true; -} diff --git a/src/network/netswitch.h b/src/network/netswitch.h deleted file mode 100644 index 69062b66c9d..00000000000 --- a/src/network/netswitch.h +++ /dev/null @@ -1,295 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Network Switch backend - * - * Authors: cold-brewed - * - * Copyright 2024 cold-brewed - */ -#ifndef NET_SWITCH_H -#define NET_SWITCH_H - -#ifdef _WIN32 -#include // before Windows.h, else Winsock 1 conflict -#include // needed for ip_mreq definition for multicast -#include -#else -#include -#include -#include -#include -#include -#endif -#include -#include "pb.h" -#include "networkmessage.pb.h" - -/* Local switch multicast port */ -#define NET_SWITCH_MULTICAST_PORT 8086 -/* Remote switch connect port */ -#define NET_SWITCH_REMOTE_PORT 8088 -/* Remove switch. This offset is where the local source ports will begin. */ -#define NET_SWITCH_RECV_PORT_OFFSET 198 -/* Multicast group (IP Address) maximum length. String representation. */ -#define MAX_MCAST_GROUP_LEN 32 -/* The buffer length used for both receiving on sockets and protobuf serialize / deserialize */ -#define NET_SWITCH_BUFFER_LENGTH 2048 - -/* Any frame above this size gets fragmented */ -#define MAX_FRAME_SEND_SIZE 1200 -/* Minimum fragment size we'll accept */ -#define MIN_FRAG_RECV_SIZE 12 -/* - Size of the fragment buffer - how many can we hold? - Note: FRAGMENT_BUFFER_LENGTH * MIN_FRAG_RECV_SIZE *must* be greater - than NET_MAX_FRAME or bad things will happen with large packets! -*/ -#define FRAGMENT_BUFFER_LENGTH 128 -/* Maximum number of switch groups */ -#define MAX_SWITCH_GROUP 31 -/* Size of a mac address in bytes. Used for the protobuf serializing / deserializing */ -#define PB_MAC_ADDR_SIZE 6 -/* This will define the version in use and the minimum required for communication */ -#define NS_PROTOCOL_VERSION 1 -/* Maximum string size for a printable (formatted) mac address */ -#define MAX_PRINTABLE_MAC 32 -/* Maximum hostname length for a remote switch host */ -#define MAX_HOSTNAME 128 - -typedef enum { - FLAGS_NONE = 0, - FLAGS_PROMISC = 1 << 0, -} ns_flags_t; - -typedef enum { - SWITCH_TYPE_LOCAL = 0, - SWITCH_TYPE_REMOTE, -} ns_type_t; - -typedef enum { - DISCONNECTED, - CONNECTING, - CONNECTED, - LOCAL, -} ns_client_state_t; - -struct ns_open_args { - uint8_t group; - ns_flags_t flags; - ns_type_t type; - char *client_id; - uint8_t mac_addr[6]; - char nrs_hostname[MAX_HOSTNAME]; -}; - -struct nsconn; - -typedef struct nsconn NSCONN; - -struct ns_stats { - size_t max_tx_frame; - size_t max_tx_packet; - size_t max_rx_frame; - size_t max_rx_packet; - uint8_t last_tx_ethertype[2]; - uint8_t last_rx_ethertype[2]; - u_long total_rx_packets; - u_long total_tx_packets; - u_long total_fragments; - uint8_t max_vec; -}; - -typedef struct { - /* The ID of the fragment. All fragments in a set should have the same ID. */ - uint32_t id; - /* The fragment index in the sequence of fragments. NOTE: one indexed, not zero! - * Example: the first fragment of three would be 1 in the sequence */ - uint32_t sequence; - /* Total number of fragments for the collection */ - uint32_t total; - /* The sequence number of the packet that delivered the fragment. Not the same as fragment sequence above! */ - uint32_t packet_sequence; - /* Frame data */ - char *data; - /* Frame size. A size of zero indicates an unused fragment slot and unallocated data field. */ - uint32_t size; - /* Epoch time (in ms) that the fragment is valid until */ - uint64_t ttl; -} ns_fragment_t; - -struct nsconn { - uint16_t flags; - int fdctl; - int fddata; - int fdout; - char mcast_group[MAX_MCAST_GROUP_LEN]; - struct sockaddr_in addr; - struct sockaddr_in outaddr; - size_t outlen; - struct sockaddr *sock; - struct sockaddr *outsock; - struct ns_stats stats; - uint32_t client_id; - uint8_t mac_addr[6]; - uint16_t sequence; - uint16_t remote_sequence; - uint8_t version; - uint8_t switch_type; - ns_client_state_t client_state; - int64_t last_packet_stamp; - /* Remote switch hostname */ - char nrs_hostname[MAX_HOSTNAME]; - /* Remote connect port for remote network switch */ - uint16_t remote_network_port; - /* Local multicast port for the local network switch */ - uint16_t local_multicast_port; - /* - * The source port to receive packets. Only applies to remote mode. - * This will also be the source port for sent packets in order to aid - * NAT - */ - uint16_t remote_source_port; - ns_fragment_t *fragment_buffer[FRAGMENT_BUFFER_LENGTH]; -}; - -typedef struct { - uint32_t id; - uint32_t history; -} ns_ack_t; - -typedef struct { - uint32_t id; - uint32_t sequence; - uint32_t total; -} ns_fragment_info_t; - -typedef struct { - netpkt_t pkt; - MessageType type; - uint32_t client_id; - uint8_t mac[6]; - uint32_t flags; - int64_t timestamp; - ns_ack_t ack; - ns_fragment_info_t fragment; - uint32_t version; -} ns_rx_packet_t; - -typedef struct { - size_t size; - char src_mac_h[MAX_PRINTABLE_MAC]; - char dest_mac_h[MAX_PRINTABLE_MAC]; - char my_mac_h[MAX_PRINTABLE_MAC]; - uint8_t src_mac[6]; - uint8_t dest_mac[6]; - bool is_packet_from_me; - bool is_broadcast; - bool is_packet_for_me; - bool is_data_packet; - char printable[128]; -} data_packet_info_t; - -typedef struct { - uint8_t src_mac[6]; - char src_mac_h[MAX_PRINTABLE_MAC]; - bool is_packet_from_me; - MessageType type; - char printable[128]; - uint64_t client_id; - int64_t timestamp; -} control_packet_info_t; - -/* Initializes and opens the Net Multicast Switch */ -NSCONN *ns_open(struct ns_open_args *open_args); - -/* Returns the flags */ -int ns_flags(const NSCONN *conn); - -/* Returns the file descriptor for polling */ -int ns_pollfd(const NSCONN *conn); - -/* This should be used to receive serialized protobuf packets - * and have the output placed in the packet struct */ -bool ns_recv_pb(NSCONN *conn, ns_rx_packet_t *packet,size_t len,int flags); - -/* Do not call directly! Used internally */ -ssize_t ns_sock_recv(const NSCONN *conn,void *buf,size_t len,int flags); - -/* This should be used to send serialized protobuf packets -* and have the output placed in the packet struct */ -ssize_t ns_send_pb(NSCONN *conn, const netpkt_t *packet,int flags); - -/* Send control messages */ -bool ns_send_control(NSCONN *conn, MessageType type); - -const char* ns_printable_message_type(MessageType type); - -/* Do not call directly! Used internally */ -ssize_t ns_sock_send(NSCONN *conn,const void *buf,size_t len,int flags); - -uint32_t ns_gen_client_id(void); - -/* Closes and cleans up */ -int ns_close(NSCONN *conn); - -/* Return current time in milliseconds */ -int64_t ns_get_current_millis(void); - -/* Is the packet a control packet? - * Any type other than DATA is a control packet, including fragments */ -bool is_control_packet(const ns_rx_packet_t *packet); - -/* Logic for handling control packets */ -bool process_control_packet(NSCONN *conn, const ns_rx_packet_t *packet); - -/* Is the packet a fragment packet? */ -bool is_fragment_packet(const ns_rx_packet_t *packet); - -/* Store a fragment in the fragment buffer */ -bool store_fragment(const NSCONN *conn, const NetworkMessage *network_message); - -/* Reassemble a fragment from the fragment buffer */ -bool reassemble_fragment(const NSCONN *conn, netpkt_t *pkt, uint32_t packet_count); - -/* Set up the socket. Accounts for the differences between local and remote modes */ -bool ns_socket_setup(NSCONN *conn); - -/* Is the switch in a connected state? Always returns true in local mode */ -bool ns_connected(const NSCONN *conn); - -/* Return a string with a properly formatted mac address. - * Note: Caller must free! */ -char* formatted_mac(uint8_t mac_addr[6]); - -/* Used for control packet info and logic */ -control_packet_info_t get_control_packet_info(ns_rx_packet_t packet, const uint8_t *my_mac); - -/* Used for data packet info and logic */ -data_packet_info_t get_data_packet_info(const netpkt_t *packet, const uint8_t *my_mac); - -/* Checks for a valid file descriptor */ -bool fd_valid(int fd); - -/* Wrapping increment for the sequence number */ -bool seq_increment(NSCONN *conn); - -#ifdef ENABLE_NET_SWITCH_LOG -static void -net_switch_log(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); -} -#else -# define net_switch_log(fmt, ...) -#endif - -#endif \ No newline at end of file diff --git a/src/network/network.c b/src/network/network.c index 3f854f35656..1a23c428090 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -52,9 +52,7 @@ #include #include #include -#ifndef _MSC_VER #include -#endif #include #define HAVE_STDARG_H #include <86box/86box.h> @@ -501,13 +499,11 @@ network_attach(void *card_drv, uint8_t *mac, NETRXCB rx, NETSETLINKSTATE set_lin card->host_drv.priv = card->host_drv.init(card, mac, net_cards_conf[net_card_current].host_dev_name, net_drv_error); break; #endif -#ifdef USE_NETSWITCH - case NET_TYPE_NMSWITCH: + case NET_TYPE_NLSWITCH: case NET_TYPE_NRSWITCH: - card->host_drv = net_netswitch_drv; + card->host_drv = net_switch_drv; card->host_drv.priv = card->host_drv.init(card, mac, &net_cards_conf[net_card_current], net_drv_error); break; -#endif /* USE_NETSWITCH */ default: card->host_drv.priv = NULL; break; @@ -519,14 +515,6 @@ network_attach(void *card_drv, uint8_t *mac, NETRXCB rx, NETSETLINKSTATE set_lin if (!card->host_drv.priv) { if(net_cards_conf[net_card_current].net_type != NET_TYPE_NONE) { -#ifdef USE_NETSWITCH - // FIXME: Hardcoded during dev - // FIXME: Remove when done! - if((net_cards_conf[net_card_current].net_type == NET_TYPE_NMSWITCH) || - (net_cards_conf[net_card_current].net_type == NET_TYPE_NRSWITCH)) - fatal("%s", net_drv_error); -#endif /* USE_NETSWITCH */ - // We're here because of a failure swprintf(tempmsg, sizeof_w(tempmsg), L"%ls:\n\n%s\n\n%ls", plat_get_string(STRING_NET_ERROR), net_drv_error, plat_get_string(STRING_NET_ERROR_DESC)); ui_msgbox(MBX_ERROR, tempmsg); diff --git a/src/network/networkmessage.pb.c b/src/network/networkmessage.pb.c deleted file mode 100644 index c15f03e0165..00000000000 --- a/src/network/networkmessage.pb.c +++ /dev/null @@ -1,19 +0,0 @@ -/* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.8-dev */ - -#include "networkmessage.pb.h" -#if PB_PROTO_HEADER_VERSION != 40 -#error Regenerate this file with the current version of nanopb generator. -#endif - -PB_BIND(Fragment, Fragment, AUTO) - - -PB_BIND(Ack, Ack, AUTO) - - -PB_BIND(NetworkMessage, NetworkMessage, AUTO) - - - - diff --git a/src/network/networkmessage.pb.h b/src/network/networkmessage.pb.h deleted file mode 100644 index 0a74e55b9e1..00000000000 --- a/src/network/networkmessage.pb.h +++ /dev/null @@ -1,140 +0,0 @@ -/* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.8-dev */ - -#ifndef PB_NETWORKMESSAGE_PB_H_INCLUDED -#define PB_NETWORKMESSAGE_PB_H_INCLUDED -#include "pb.h" - -#if PB_PROTO_HEADER_VERSION != 40 -#error Regenerate this file with the current version of nanopb generator. -#endif - -/* Enum definitions */ -typedef enum _MessageType { - MessageType_MESSAGE_TYPE_UNSPECIFIED = 0, - MessageType_MESSAGE_TYPE_DATA = 1, - MessageType_MESSAGE_TYPE_JOIN = 2, - MessageType_MESSAGE_TYPE_LEAVE = 3, - MessageType_MESSAGE_TYPE_KEEPALIVE = 4, - MessageType_MESSAGE_TYPE_FRAGMENT = 5, - MessageType_MESSAGE_TYPE_ACK = 6, - MessageType_MESSAGE_TYPE_CONNECT_REQUEST = 7, - MessageType_MESSAGE_TYPE_CONNECT_REPLY = 8 -} MessageType; - -/* Struct definitions */ -typedef struct _Fragment { - uint32_t id; - uint32_t sequence; - uint32_t total; -} Fragment; - -typedef struct _Ack { - uint32_t id; - uint32_t history; -} Ack; - -typedef struct _NetworkMessage { - MessageType message_type; - uint32_t client_id; - pb_bytes_array_t *mac; - pb_bytes_array_t *frame; - uint32_t flags; - uint32_t version; - bool has_ack; - Ack ack; - bool has_fragment; - Fragment fragment; - int64_t timestamp; - uint32_t sequence; -} NetworkMessage; - - -#ifdef __cplusplus -extern "C" { -#endif - -/* Helper constants for enums */ -#define _MessageType_MIN MessageType_MESSAGE_TYPE_UNSPECIFIED -#define _MessageType_MAX MessageType_MESSAGE_TYPE_CONNECT_REPLY -#define _MessageType_ARRAYSIZE ((MessageType)(MessageType_MESSAGE_TYPE_CONNECT_REPLY+1)) - - - -#define NetworkMessage_message_type_ENUMTYPE MessageType - - -/* Initializer values for message structs */ -#define Fragment_init_default {0, 0, 0} -#define Ack_init_default {0, 0} -#define NetworkMessage_init_default {_MessageType_MIN, 0, NULL, NULL, 0, 0, false, Ack_init_default, false, Fragment_init_default, 0, 0} -#define Fragment_init_zero {0, 0, 0} -#define Ack_init_zero {0, 0} -#define NetworkMessage_init_zero {_MessageType_MIN, 0, NULL, NULL, 0, 0, false, Ack_init_zero, false, Fragment_init_zero, 0, 0} - -/* Field tags (for use in manual encoding/decoding) */ -#define Fragment_id_tag 1 -#define Fragment_sequence_tag 2 -#define Fragment_total_tag 3 -#define Ack_id_tag 1 -#define Ack_history_tag 2 -#define NetworkMessage_message_type_tag 1 -#define NetworkMessage_client_id_tag 2 -#define NetworkMessage_mac_tag 3 -#define NetworkMessage_frame_tag 4 -#define NetworkMessage_flags_tag 5 -#define NetworkMessage_version_tag 6 -#define NetworkMessage_ack_tag 7 -#define NetworkMessage_fragment_tag 8 -#define NetworkMessage_timestamp_tag 9 -#define NetworkMessage_sequence_tag 10 - -/* Struct field encoding specification for nanopb */ -#define Fragment_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT32, id, 1) \ -X(a, STATIC, SINGULAR, UINT32, sequence, 2) \ -X(a, STATIC, SINGULAR, UINT32, total, 3) -#define Fragment_CALLBACK NULL -#define Fragment_DEFAULT NULL - -#define Ack_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT32, id, 1) \ -X(a, STATIC, SINGULAR, UINT32, history, 2) -#define Ack_CALLBACK NULL -#define Ack_DEFAULT NULL - -#define NetworkMessage_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, message_type, 1) \ -X(a, STATIC, SINGULAR, UINT32, client_id, 2) \ -X(a, POINTER, SINGULAR, BYTES, mac, 3) \ -X(a, POINTER, SINGULAR, BYTES, frame, 4) \ -X(a, STATIC, SINGULAR, UINT32, flags, 5) \ -X(a, STATIC, SINGULAR, UINT32, version, 6) \ -X(a, STATIC, OPTIONAL, MESSAGE, ack, 7) \ -X(a, STATIC, OPTIONAL, MESSAGE, fragment, 8) \ -X(a, STATIC, SINGULAR, INT64, timestamp, 9) \ -X(a, STATIC, SINGULAR, UINT32, sequence, 10) -#define NetworkMessage_CALLBACK NULL -#define NetworkMessage_DEFAULT NULL -#define NetworkMessage_ack_MSGTYPE Ack -#define NetworkMessage_fragment_MSGTYPE Fragment - -extern const pb_msgdesc_t Fragment_msg; -extern const pb_msgdesc_t Ack_msg; -extern const pb_msgdesc_t NetworkMessage_msg; - -/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ -#define Fragment_fields &Fragment_msg -#define Ack_fields &Ack_msg -#define NetworkMessage_fields &NetworkMessage_msg - -/* Maximum encoded size of messages (where known) */ -/* NetworkMessage_size depends on runtime parameters */ -#define Ack_size 12 -#define Fragment_size 18 - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif diff --git a/src/network/networkmessage.proto.txt b/src/network/networkmessage.proto.txt deleted file mode 100644 index 9511f17c89c..00000000000 --- a/src/network/networkmessage.proto.txt +++ /dev/null @@ -1,38 +0,0 @@ -syntax = "proto3"; -import "nanopb.proto"; - -enum MessageType { - MESSAGE_TYPE_UNSPECIFIED = 0; - MESSAGE_TYPE_DATA = 1; - MESSAGE_TYPE_JOIN = 2; - MESSAGE_TYPE_LEAVE = 3; - MESSAGE_TYPE_KEEPALIVE = 4; - MESSAGE_TYPE_FRAGMENT = 5; - MESSAGE_TYPE_ACK = 6; - MESSAGE_TYPE_CONNECT_REQUEST = 7; - MESSAGE_TYPE_CONNECT_REPLY = 8; -} - -message Fragment { - uint32 id = 1; - uint32 sequence = 2; - uint32 total = 3; -} - -message Ack { - uint32 id = 1; - uint32 history = 2; -} - -message NetworkMessage { - MessageType message_type = 1; - uint32 client_id = 2; - bytes mac = 3 [(nanopb).type = FT_POINTER]; - bytes frame = 4 [(nanopb).type = FT_POINTER]; - uint32 flags = 5; - uint32 version = 6; - Ack ack = 7; - Fragment fragment = 8; - int64 timestamp = 9; - uint32 sequence = 10; -} \ No newline at end of file diff --git a/src/network/pb.h b/src/network/pb.h deleted file mode 100644 index 7433ac24b08..00000000000 --- a/src/network/pb.h +++ /dev/null @@ -1,917 +0,0 @@ -/* Common parts of the nanopb library. Most of these are quite low-level - * stuff. For the high-level interface, see pb_encode.h and pb_decode.h. - */ - -#ifndef PB_H_INCLUDED -#define PB_H_INCLUDED - -/***************************************************************** - * Nanopb compilation time options. You can change these here by * - * uncommenting the lines, or on the compiler command line. * - *****************************************************************/ - -/* Enable support for dynamically allocated fields */ -#define PB_ENABLE_MALLOC 1 - -/* Define this if your CPU / compiler combination does not support - * unaligned memory access to packed structures. Note that packed - * structures are only used when requested in .proto options. */ -/* #define PB_NO_PACKED_STRUCTS 1 */ - -/* Increase the number of required fields that are tracked. - * A compiler warning will tell if you need this. */ -/* #define PB_MAX_REQUIRED_FIELDS 256 */ - -/* Add support for tag numbers > 65536 and fields larger than 65536 bytes. */ -/* #define PB_FIELD_32BIT 1 */ - -/* Disable support for error messages in order to save some code space. */ -/* #define PB_NO_ERRMSG 1 */ - -/* Disable support for custom streams (support only memory buffers). */ -#define PB_BUFFER_ONLY 1 - -/* Disable support for 64-bit datatypes, for compilers without int64_t - or to save some code space. */ -/* #define PB_WITHOUT_64BIT 1 */ - -/* Don't encode scalar arrays as packed. This is only to be used when - * the decoder on the receiving side cannot process packed scalar arrays. - * Such example is older protobuf.js. */ -/* #define PB_ENCODE_ARRAYS_UNPACKED 1 */ - -/* Enable conversion of doubles to floats for platforms that do not - * support 64-bit doubles. Most commonly AVR. */ -/* #define PB_CONVERT_DOUBLE_FLOAT 1 */ - -/* Check whether incoming strings are valid UTF-8 sequences. Slows down - * the string processing slightly and slightly increases code size. */ -/* #define PB_VALIDATE_UTF8 1 */ - -/* This can be defined if the platform is little-endian and has 8-bit bytes. - * Normally it is automatically detected based on __BYTE_ORDER__ macro. */ -/* #define PB_LITTLE_ENDIAN_8BIT 1 */ - -/* Configure static assert mechanism. Instead of changing these, set your - * compiler to C11 standard mode if possible. */ -/* #define PB_C99_STATIC_ASSERT 1 */ -/* #define PB_NO_STATIC_ASSERT 1 */ - -/****************************************************************** - * You usually don't need to change anything below this line. * - * Feel free to look around and use the defined macros, though. * - ******************************************************************/ - - -/* Version of the nanopb library. Just in case you want to check it in - * your own program. */ -#define NANOPB_VERSION "nanopb-0.4.8-dev" - -/* Include all the system headers needed by nanopb. You will need the - * definitions of the following: - * - strlen, memcpy, memset functions - * - [u]int_least8_t, uint_fast8_t, [u]int_least16_t, [u]int32_t, [u]int64_t - * - size_t - * - bool - * - * If you don't have the standard header files, you can instead provide - * a custom header that defines or includes all this. In that case, - * define PB_SYSTEM_HEADER to the path of this file. - */ -#ifdef PB_SYSTEM_HEADER -#include PB_SYSTEM_HEADER -#else -#include -#include -#include -#include -#include - -#ifdef PB_ENABLE_MALLOC -#include -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* Macro for defining packed structures (compiler dependent). - * This just reduces memory requirements, but is not required. - */ -#if defined(PB_NO_PACKED_STRUCTS) - /* Disable struct packing */ -# define PB_PACKED_STRUCT_START -# define PB_PACKED_STRUCT_END -# define pb_packed -#elif defined(__GNUC__) || defined(__clang__) - /* For GCC and clang */ -# define PB_PACKED_STRUCT_START -# define PB_PACKED_STRUCT_END -# define pb_packed __attribute__((packed)) -#elif defined(__ICCARM__) || defined(__CC_ARM) - /* For IAR ARM and Keil MDK-ARM compilers */ -# define PB_PACKED_STRUCT_START _Pragma("pack(push, 1)") -# define PB_PACKED_STRUCT_END _Pragma("pack(pop)") -# define pb_packed -#elif defined(_MSC_VER) && (_MSC_VER >= 1500) - /* For Microsoft Visual C++ */ -# define PB_PACKED_STRUCT_START __pragma(pack(push, 1)) -# define PB_PACKED_STRUCT_END __pragma(pack(pop)) -# define pb_packed -#else - /* Unknown compiler */ -# define PB_PACKED_STRUCT_START -# define PB_PACKED_STRUCT_END -# define pb_packed -#endif - -/* Detect endianness */ -#ifndef PB_LITTLE_ENDIAN_8BIT -#if ((defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN) || \ - (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \ - defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || \ - defined(__THUMBEL__) || defined(__AARCH64EL__) || defined(_MIPSEL) || \ - defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM)) \ - && CHAR_BIT == 8 -#define PB_LITTLE_ENDIAN_8BIT 1 -#endif -#endif - -/* Handly macro for suppressing unreferenced-parameter compiler warnings. */ -#ifndef PB_UNUSED -#define PB_UNUSED(x) (void)(x) -#endif - -/* Harvard-architecture processors may need special attributes for storing - * field information in program memory. */ -#ifndef PB_PROGMEM -#ifdef __AVR__ -#include -#define PB_PROGMEM PROGMEM -#define PB_PROGMEM_READU32(x) pgm_read_dword(&x) -#else -#define PB_PROGMEM -#define PB_PROGMEM_READU32(x) (x) -#endif -#endif - -/* Compile-time assertion, used for checking compatible compilation options. - * If this does not work properly on your compiler, use - * #define PB_NO_STATIC_ASSERT to disable it. - * - * But before doing that, check carefully the error message / place where it - * comes from to see if the error has a real cause. Unfortunately the error - * message is not always very clear to read, but you can see the reason better - * in the place where the PB_STATIC_ASSERT macro was called. - */ -#ifndef PB_NO_STATIC_ASSERT -# ifndef PB_STATIC_ASSERT -# if defined(__ICCARM__) - /* IAR has static_assert keyword but no _Static_assert */ -# define PB_STATIC_ASSERT(COND,MSG) static_assert(COND,#MSG); -# elif defined(_MSC_VER) && (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 201112) - /* MSVC in C89 mode supports static_assert() keyword anyway */ -# define PB_STATIC_ASSERT(COND,MSG) static_assert(COND,#MSG); -# elif defined(PB_C99_STATIC_ASSERT) - /* Classic negative-size-array static assert mechanism */ -# define PB_STATIC_ASSERT(COND,MSG) typedef char PB_STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND)?1:-1]; -# define PB_STATIC_ASSERT_MSG(MSG, LINE, COUNTER) PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) -# define PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) pb_static_assertion_##MSG##_##LINE##_##COUNTER -# elif defined(__cplusplus) - /* C++11 standard static_assert mechanism */ -# define PB_STATIC_ASSERT(COND,MSG) static_assert(COND,#MSG); -# else - /* C11 standard _Static_assert mechanism */ -# define PB_STATIC_ASSERT(COND,MSG) _Static_assert(COND,#MSG); -# endif -# endif -#else - /* Static asserts disabled by PB_NO_STATIC_ASSERT */ -# define PB_STATIC_ASSERT(COND,MSG) -#endif - -/* Test that PB_STATIC_ASSERT works - * If you get errors here, you may need to do one of these: - * - Enable C11 standard support in your compiler - * - Define PB_C99_STATIC_ASSERT to enable C99 standard support - * - Define PB_NO_STATIC_ASSERT to disable static asserts altogether - */ -PB_STATIC_ASSERT(1, STATIC_ASSERT_IS_NOT_WORKING) - -/* Number of required fields to keep track of. */ -#ifndef PB_MAX_REQUIRED_FIELDS -#define PB_MAX_REQUIRED_FIELDS 64 -#endif - -#if PB_MAX_REQUIRED_FIELDS < 64 -#error You should not lower PB_MAX_REQUIRED_FIELDS from the default value (64). -#endif - -#ifdef PB_WITHOUT_64BIT -#ifdef PB_CONVERT_DOUBLE_FLOAT -/* Cannot use doubles without 64-bit types */ -#undef PB_CONVERT_DOUBLE_FLOAT -#endif -#endif - -/* List of possible field types. These are used in the autogenerated code. - * Least-significant 4 bits tell the scalar type - * Most-significant 4 bits specify repeated/required/packed etc. - */ - -typedef uint_least8_t pb_type_t; - -/**** Field data types ****/ - -/* Numeric types */ -#define PB_LTYPE_BOOL 0x00U /* bool */ -#define PB_LTYPE_VARINT 0x01U /* int32, int64, enum, bool */ -#define PB_LTYPE_UVARINT 0x02U /* uint32, uint64 */ -#define PB_LTYPE_SVARINT 0x03U /* sint32, sint64 */ -#define PB_LTYPE_FIXED32 0x04U /* fixed32, sfixed32, float */ -#define PB_LTYPE_FIXED64 0x05U /* fixed64, sfixed64, double */ - -/* Marker for last packable field type. */ -#define PB_LTYPE_LAST_PACKABLE 0x05U - -/* Byte array with pre-allocated buffer. - * data_size is the length of the allocated PB_BYTES_ARRAY structure. */ -#define PB_LTYPE_BYTES 0x06U - -/* String with pre-allocated buffer. - * data_size is the maximum length. */ -#define PB_LTYPE_STRING 0x07U - -/* Submessage - * submsg_fields is pointer to field descriptions */ -#define PB_LTYPE_SUBMESSAGE 0x08U - -/* Submessage with pre-decoding callback - * The pre-decoding callback is stored as pb_callback_t right before pSize. - * submsg_fields is pointer to field descriptions */ -#define PB_LTYPE_SUBMSG_W_CB 0x09U - -/* Extension pseudo-field - * The field contains a pointer to pb_extension_t */ -#define PB_LTYPE_EXTENSION 0x0AU - -/* Byte array with inline, pre-allocated byffer. - * data_size is the length of the inline, allocated buffer. - * This differs from PB_LTYPE_BYTES by defining the element as - * pb_byte_t[data_size] rather than pb_bytes_array_t. */ -#define PB_LTYPE_FIXED_LENGTH_BYTES 0x0BU - -/* Number of declared LTYPES */ -#define PB_LTYPES_COUNT 0x0CU -#define PB_LTYPE_MASK 0x0FU - -/**** Field repetition rules ****/ - -#define PB_HTYPE_REQUIRED 0x00U -#define PB_HTYPE_OPTIONAL 0x10U -#define PB_HTYPE_SINGULAR 0x10U -#define PB_HTYPE_REPEATED 0x20U -#define PB_HTYPE_FIXARRAY 0x20U -#define PB_HTYPE_ONEOF 0x30U -#define PB_HTYPE_MASK 0x30U - -/**** Field allocation types ****/ - -#define PB_ATYPE_STATIC 0x00U -#define PB_ATYPE_POINTER 0x80U -#define PB_ATYPE_CALLBACK 0x40U -#define PB_ATYPE_MASK 0xC0U - -#define PB_ATYPE(x) ((x) & PB_ATYPE_MASK) -#define PB_HTYPE(x) ((x) & PB_HTYPE_MASK) -#define PB_LTYPE(x) ((x) & PB_LTYPE_MASK) -#define PB_LTYPE_IS_SUBMSG(x) (PB_LTYPE(x) == PB_LTYPE_SUBMESSAGE || \ - PB_LTYPE(x) == PB_LTYPE_SUBMSG_W_CB) - -/* Data type used for storing sizes of struct fields - * and array counts. - */ -#if defined(PB_FIELD_32BIT) - typedef uint32_t pb_size_t; - typedef int32_t pb_ssize_t; -#else - typedef uint_least16_t pb_size_t; - typedef int_least16_t pb_ssize_t; -#endif -#define PB_SIZE_MAX ((pb_size_t)-1) - -/* Data type for storing encoded data and other byte streams. - * This typedef exists to support platforms where uint8_t does not exist. - * You can regard it as equivalent on uint8_t on other platforms. - */ -typedef uint_least8_t pb_byte_t; - -/* Forward declaration of struct types */ -typedef struct pb_istream_s pb_istream_t; -typedef struct pb_ostream_s pb_ostream_t; -typedef struct pb_field_iter_s pb_field_iter_t; - -/* This structure is used in auto-generated constants - * to specify struct fields. - */ -typedef struct pb_msgdesc_s pb_msgdesc_t; -struct pb_msgdesc_s { - const uint32_t *field_info; - const pb_msgdesc_t * const * submsg_info; - const pb_byte_t *default_value; - - bool (*field_callback)(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field); - - pb_size_t field_count; - pb_size_t required_field_count; - pb_size_t largest_tag; -}; - -/* Iterator for message descriptor */ -struct pb_field_iter_s { - const pb_msgdesc_t *descriptor; /* Pointer to message descriptor constant */ - void *message; /* Pointer to start of the structure */ - - pb_size_t index; /* Index of the field */ - pb_size_t field_info_index; /* Index to descriptor->field_info array */ - pb_size_t required_field_index; /* Index that counts only the required fields */ - pb_size_t submessage_index; /* Index that counts only submessages */ - - pb_size_t tag; /* Tag of current field */ - pb_size_t data_size; /* sizeof() of a single item */ - pb_size_t array_size; /* Number of array entries */ - pb_type_t type; /* Type of current field */ - - void *pField; /* Pointer to current field in struct */ - void *pData; /* Pointer to current data contents. Different than pField for arrays and pointers. */ - void *pSize; /* Pointer to count/has field */ - - const pb_msgdesc_t *submsg_desc; /* For submessage fields, pointer to field descriptor for the submessage. */ -}; - -/* For compatibility with legacy code */ -typedef pb_field_iter_t pb_field_t; - -/* Make sure that the standard integer types are of the expected sizes. - * Otherwise fixed32/fixed64 fields can break. - * - * If you get errors here, it probably means that your stdint.h is not - * correct for your platform. - */ -#ifndef PB_WITHOUT_64BIT -PB_STATIC_ASSERT(sizeof(int64_t) == 2 * sizeof(int32_t), INT64_T_WRONG_SIZE) -PB_STATIC_ASSERT(sizeof(uint64_t) == 2 * sizeof(uint32_t), UINT64_T_WRONG_SIZE) -#endif - -/* This structure is used for 'bytes' arrays. - * It has the number of bytes in the beginning, and after that an array. - * Note that actual structs used will have a different length of bytes array. - */ -#define PB_BYTES_ARRAY_T(n) struct { pb_size_t size; pb_byte_t bytes[n]; } -#define PB_BYTES_ARRAY_T_ALLOCSIZE(n) ((size_t)n + offsetof(pb_bytes_array_t, bytes)) - -struct pb_bytes_array_s { - pb_size_t size; - pb_byte_t bytes[1]; -}; -typedef struct pb_bytes_array_s pb_bytes_array_t; - -/* This structure is used for giving the callback function. - * It is stored in the message structure and filled in by the method that - * calls pb_decode. - * - * The decoding callback will be given a limited-length stream - * If the wire type was string, the length is the length of the string. - * If the wire type was a varint/fixed32/fixed64, the length is the length - * of the actual value. - * The function may be called multiple times (especially for repeated types, - * but also otherwise if the message happens to contain the field multiple - * times.) - * - * The encoding callback will receive the actual output stream. - * It should write all the data in one call, including the field tag and - * wire type. It can write multiple fields. - * - * The callback can be null if you want to skip a field. - */ -typedef struct pb_callback_s pb_callback_t; -struct pb_callback_s { - /* Callback functions receive a pointer to the arg field. - * You can access the value of the field as *arg, and modify it if needed. - */ - union { - bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void **arg); - bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, void * const *arg); - } funcs; - - /* Free arg for use by callback */ - void *arg; -}; - -extern bool pb_default_field_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_t *field); - -/* Wire types. Library user needs these only in encoder callbacks. */ -typedef enum { - PB_WT_VARINT = 0, - PB_WT_64BIT = 1, - PB_WT_STRING = 2, - PB_WT_32BIT = 5, - PB_WT_PACKED = 255 /* PB_WT_PACKED is internal marker for packed arrays. */ -} pb_wire_type_t; - -/* Structure for defining the handling of unknown/extension fields. - * Usually the pb_extension_type_t structure is automatically generated, - * while the pb_extension_t structure is created by the user. However, - * if you want to catch all unknown fields, you can also create a custom - * pb_extension_type_t with your own callback. - */ -typedef struct pb_extension_type_s pb_extension_type_t; -typedef struct pb_extension_s pb_extension_t; -struct pb_extension_type_s { - /* Called for each unknown field in the message. - * If you handle the field, read off all of its data and return true. - * If you do not handle the field, do not read anything and return true. - * If you run into an error, return false. - * Set to NULL for default handler. - */ - bool (*decode)(pb_istream_t *stream, pb_extension_t *extension, - uint32_t tag, pb_wire_type_t wire_type); - - /* Called once after all regular fields have been encoded. - * If you have something to write, do so and return true. - * If you do not have anything to write, just return true. - * If you run into an error, return false. - * Set to NULL for default handler. - */ - bool (*encode)(pb_ostream_t *stream, const pb_extension_t *extension); - - /* Free field for use by the callback. */ - const void *arg; -}; - -struct pb_extension_s { - /* Type describing the extension field. Usually you'll initialize - * this to a pointer to the automatically generated structure. */ - const pb_extension_type_t *type; - - /* Destination for the decoded data. This must match the datatype - * of the extension field. */ - void *dest; - - /* Pointer to the next extension handler, or NULL. - * If this extension does not match a field, the next handler is - * automatically called. */ - pb_extension_t *next; - - /* The decoder sets this to true if the extension was found. - * Ignored for encoding. */ - bool found; -}; - -#define pb_extension_init_zero {NULL,NULL,NULL,false} - -/* Memory allocation functions to use. You can define pb_realloc and - * pb_free to custom functions if you want. */ -#ifdef PB_ENABLE_MALLOC -# ifndef pb_realloc -# define pb_realloc(ptr, size) realloc(ptr, size) -# endif -# ifndef pb_free -# define pb_free(ptr) free(ptr) -# endif -#endif - -/* This is used to inform about need to regenerate .pb.h/.pb.c files. */ -#define PB_PROTO_HEADER_VERSION 40 - -/* These macros are used to declare pb_field_t's in the constant array. */ -/* Size of a structure member, in bytes. */ -#define pb_membersize(st, m) (sizeof ((st*)0)->m) -/* Number of entries in an array. */ -#define pb_arraysize(st, m) (pb_membersize(st, m) / pb_membersize(st, m[0])) -/* Delta from start of one member to the start of another member. */ -#define pb_delta(st, m1, m2) ((int)offsetof(st, m1) - (int)offsetof(st, m2)) - -/* Force expansion of macro value */ -#define PB_EXPAND(x) x - -/* Binding of a message field set into a specific structure */ -#define PB_BIND(msgname, structname, width) \ - const uint32_t structname ## _field_info[] PB_PROGMEM = \ - { \ - msgname ## _FIELDLIST(PB_GEN_FIELD_INFO_ ## width, structname) \ - 0 \ - }; \ - const pb_msgdesc_t* const structname ## _submsg_info[] = \ - { \ - msgname ## _FIELDLIST(PB_GEN_SUBMSG_INFO, structname) \ - NULL \ - }; \ - const pb_msgdesc_t structname ## _msg = \ - { \ - structname ## _field_info, \ - structname ## _submsg_info, \ - msgname ## _DEFAULT, \ - msgname ## _CALLBACK, \ - 0 msgname ## _FIELDLIST(PB_GEN_FIELD_COUNT, structname), \ - 0 msgname ## _FIELDLIST(PB_GEN_REQ_FIELD_COUNT, structname), \ - 0 msgname ## _FIELDLIST(PB_GEN_LARGEST_TAG, structname), \ - }; \ - msgname ## _FIELDLIST(PB_GEN_FIELD_INFO_ASSERT_ ## width, structname) - -#define PB_GEN_FIELD_COUNT(structname, atype, htype, ltype, fieldname, tag) +1 -#define PB_GEN_REQ_FIELD_COUNT(structname, atype, htype, ltype, fieldname, tag) \ - + (PB_HTYPE_ ## htype == PB_HTYPE_REQUIRED) -#define PB_GEN_LARGEST_TAG(structname, atype, htype, ltype, fieldname, tag) \ - * 0 + tag - -/* X-macro for generating the entries in struct_field_info[] array. */ -#define PB_GEN_FIELD_INFO_1(structname, atype, htype, ltype, fieldname, tag) \ - PB_FIELDINFO_1(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ - PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) - -#define PB_GEN_FIELD_INFO_2(structname, atype, htype, ltype, fieldname, tag) \ - PB_FIELDINFO_2(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ - PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) - -#define PB_GEN_FIELD_INFO_4(structname, atype, htype, ltype, fieldname, tag) \ - PB_FIELDINFO_4(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ - PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) - -#define PB_GEN_FIELD_INFO_8(structname, atype, htype, ltype, fieldname, tag) \ - PB_FIELDINFO_8(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ - PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) - -#define PB_GEN_FIELD_INFO_AUTO(structname, atype, htype, ltype, fieldname, tag) \ - PB_FIELDINFO_AUTO2(PB_FIELDINFO_WIDTH_AUTO(_PB_ATYPE_ ## atype, _PB_HTYPE_ ## htype, _PB_LTYPE_ ## ltype), \ - tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ - PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) - -#define PB_FIELDINFO_AUTO2(width, tag, type, data_offset, data_size, size_offset, array_size) \ - PB_FIELDINFO_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size) - -#define PB_FIELDINFO_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size) \ - PB_FIELDINFO_ ## width(tag, type, data_offset, data_size, size_offset, array_size) - -/* X-macro for generating asserts that entries fit in struct_field_info[] array. - * The structure of macros here must match the structure above in PB_GEN_FIELD_INFO_x(), - * but it is not easily reused because of how macro substitutions work. */ -#define PB_GEN_FIELD_INFO_ASSERT_1(structname, atype, htype, ltype, fieldname, tag) \ - PB_FIELDINFO_ASSERT_1(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ - PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) - -#define PB_GEN_FIELD_INFO_ASSERT_2(structname, atype, htype, ltype, fieldname, tag) \ - PB_FIELDINFO_ASSERT_2(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ - PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) - -#define PB_GEN_FIELD_INFO_ASSERT_4(structname, atype, htype, ltype, fieldname, tag) \ - PB_FIELDINFO_ASSERT_4(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ - PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) - -#define PB_GEN_FIELD_INFO_ASSERT_8(structname, atype, htype, ltype, fieldname, tag) \ - PB_FIELDINFO_ASSERT_8(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ - PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) - -#define PB_GEN_FIELD_INFO_ASSERT_AUTO(structname, atype, htype, ltype, fieldname, tag) \ - PB_FIELDINFO_ASSERT_AUTO2(PB_FIELDINFO_WIDTH_AUTO(_PB_ATYPE_ ## atype, _PB_HTYPE_ ## htype, _PB_LTYPE_ ## ltype), \ - tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \ - PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \ - PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname)) - -#define PB_FIELDINFO_ASSERT_AUTO2(width, tag, type, data_offset, data_size, size_offset, array_size) \ - PB_FIELDINFO_ASSERT_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size) - -#define PB_FIELDINFO_ASSERT_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size) \ - PB_FIELDINFO_ASSERT_ ## width(tag, type, data_offset, data_size, size_offset, array_size) - -#define PB_DATA_OFFSET_STATIC(htype, structname, fieldname) PB_DO ## htype(structname, fieldname) -#define PB_DATA_OFFSET_POINTER(htype, structname, fieldname) PB_DO ## htype(structname, fieldname) -#define PB_DATA_OFFSET_CALLBACK(htype, structname, fieldname) PB_DO ## htype(structname, fieldname) -#define PB_DO_PB_HTYPE_REQUIRED(structname, fieldname) offsetof(structname, fieldname) -#define PB_DO_PB_HTYPE_SINGULAR(structname, fieldname) offsetof(structname, fieldname) -#define PB_DO_PB_HTYPE_ONEOF(structname, fieldname) offsetof(structname, PB_ONEOF_NAME(FULL, fieldname)) -#define PB_DO_PB_HTYPE_OPTIONAL(structname, fieldname) offsetof(structname, fieldname) -#define PB_DO_PB_HTYPE_REPEATED(structname, fieldname) offsetof(structname, fieldname) -#define PB_DO_PB_HTYPE_FIXARRAY(structname, fieldname) offsetof(structname, fieldname) - -#define PB_SIZE_OFFSET_STATIC(htype, structname, fieldname) PB_SO ## htype(structname, fieldname) -#define PB_SIZE_OFFSET_POINTER(htype, structname, fieldname) PB_SO_PTR ## htype(structname, fieldname) -#define PB_SIZE_OFFSET_CALLBACK(htype, structname, fieldname) PB_SO_CB ## htype(structname, fieldname) -#define PB_SO_PB_HTYPE_REQUIRED(structname, fieldname) 0 -#define PB_SO_PB_HTYPE_SINGULAR(structname, fieldname) 0 -#define PB_SO_PB_HTYPE_ONEOF(structname, fieldname) PB_SO_PB_HTYPE_ONEOF2(structname, PB_ONEOF_NAME(FULL, fieldname), PB_ONEOF_NAME(UNION, fieldname)) -#define PB_SO_PB_HTYPE_ONEOF2(structname, fullname, unionname) PB_SO_PB_HTYPE_ONEOF3(structname, fullname, unionname) -#define PB_SO_PB_HTYPE_ONEOF3(structname, fullname, unionname) pb_delta(structname, fullname, which_ ## unionname) -#define PB_SO_PB_HTYPE_OPTIONAL(structname, fieldname) pb_delta(structname, fieldname, has_ ## fieldname) -#define PB_SO_PB_HTYPE_REPEATED(structname, fieldname) pb_delta(structname, fieldname, fieldname ## _count) -#define PB_SO_PB_HTYPE_FIXARRAY(structname, fieldname) 0 -#define PB_SO_PTR_PB_HTYPE_REQUIRED(structname, fieldname) 0 -#define PB_SO_PTR_PB_HTYPE_SINGULAR(structname, fieldname) 0 -#define PB_SO_PTR_PB_HTYPE_ONEOF(structname, fieldname) PB_SO_PB_HTYPE_ONEOF(structname, fieldname) -#define PB_SO_PTR_PB_HTYPE_OPTIONAL(structname, fieldname) 0 -#define PB_SO_PTR_PB_HTYPE_REPEATED(structname, fieldname) PB_SO_PB_HTYPE_REPEATED(structname, fieldname) -#define PB_SO_PTR_PB_HTYPE_FIXARRAY(structname, fieldname) 0 -#define PB_SO_CB_PB_HTYPE_REQUIRED(structname, fieldname) 0 -#define PB_SO_CB_PB_HTYPE_SINGULAR(structname, fieldname) 0 -#define PB_SO_CB_PB_HTYPE_ONEOF(structname, fieldname) PB_SO_PB_HTYPE_ONEOF(structname, fieldname) -#define PB_SO_CB_PB_HTYPE_OPTIONAL(structname, fieldname) 0 -#define PB_SO_CB_PB_HTYPE_REPEATED(structname, fieldname) 0 -#define PB_SO_CB_PB_HTYPE_FIXARRAY(structname, fieldname) 0 - -#define PB_ARRAY_SIZE_STATIC(htype, structname, fieldname) PB_AS ## htype(structname, fieldname) -#define PB_ARRAY_SIZE_POINTER(htype, structname, fieldname) PB_AS_PTR ## htype(structname, fieldname) -#define PB_ARRAY_SIZE_CALLBACK(htype, structname, fieldname) 1 -#define PB_AS_PB_HTYPE_REQUIRED(structname, fieldname) 1 -#define PB_AS_PB_HTYPE_SINGULAR(structname, fieldname) 1 -#define PB_AS_PB_HTYPE_OPTIONAL(structname, fieldname) 1 -#define PB_AS_PB_HTYPE_ONEOF(structname, fieldname) 1 -#define PB_AS_PB_HTYPE_REPEATED(structname, fieldname) pb_arraysize(structname, fieldname) -#define PB_AS_PB_HTYPE_FIXARRAY(structname, fieldname) pb_arraysize(structname, fieldname) -#define PB_AS_PTR_PB_HTYPE_REQUIRED(structname, fieldname) 1 -#define PB_AS_PTR_PB_HTYPE_SINGULAR(structname, fieldname) 1 -#define PB_AS_PTR_PB_HTYPE_OPTIONAL(structname, fieldname) 1 -#define PB_AS_PTR_PB_HTYPE_ONEOF(structname, fieldname) 1 -#define PB_AS_PTR_PB_HTYPE_REPEATED(structname, fieldname) 1 -#define PB_AS_PTR_PB_HTYPE_FIXARRAY(structname, fieldname) pb_arraysize(structname, fieldname[0]) - -#define PB_DATA_SIZE_STATIC(htype, structname, fieldname) PB_DS ## htype(structname, fieldname) -#define PB_DATA_SIZE_POINTER(htype, structname, fieldname) PB_DS_PTR ## htype(structname, fieldname) -#define PB_DATA_SIZE_CALLBACK(htype, structname, fieldname) PB_DS_CB ## htype(structname, fieldname) -#define PB_DS_PB_HTYPE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname) -#define PB_DS_PB_HTYPE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname) -#define PB_DS_PB_HTYPE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname) -#define PB_DS_PB_HTYPE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname)) -#define PB_DS_PB_HTYPE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname[0]) -#define PB_DS_PB_HTYPE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname[0]) -#define PB_DS_PTR_PB_HTYPE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname[0]) -#define PB_DS_PTR_PB_HTYPE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname[0]) -#define PB_DS_PTR_PB_HTYPE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname[0]) -#define PB_DS_PTR_PB_HTYPE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname)[0]) -#define PB_DS_PTR_PB_HTYPE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname[0]) -#define PB_DS_PTR_PB_HTYPE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname[0][0]) -#define PB_DS_CB_PB_HTYPE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname) -#define PB_DS_CB_PB_HTYPE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname) -#define PB_DS_CB_PB_HTYPE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname) -#define PB_DS_CB_PB_HTYPE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname)) -#define PB_DS_CB_PB_HTYPE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname) -#define PB_DS_CB_PB_HTYPE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname) - -#define PB_ONEOF_NAME(type, tuple) PB_EXPAND(PB_ONEOF_NAME_ ## type tuple) -#define PB_ONEOF_NAME_UNION(unionname,membername,fullname) unionname -#define PB_ONEOF_NAME_MEMBER(unionname,membername,fullname) membername -#define PB_ONEOF_NAME_FULL(unionname,membername,fullname) fullname - -#define PB_GEN_SUBMSG_INFO(structname, atype, htype, ltype, fieldname, tag) \ - PB_SUBMSG_INFO_ ## htype(_PB_LTYPE_ ## ltype, structname, fieldname) - -#define PB_SUBMSG_INFO_REQUIRED(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE) -#define PB_SUBMSG_INFO_SINGULAR(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE) -#define PB_SUBMSG_INFO_OPTIONAL(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE) -#define PB_SUBMSG_INFO_ONEOF(ltype, structname, fieldname) PB_SUBMSG_INFO_ONEOF2(ltype, structname, PB_ONEOF_NAME(UNION, fieldname), PB_ONEOF_NAME(MEMBER, fieldname)) -#define PB_SUBMSG_INFO_ONEOF2(ltype, structname, unionname, membername) PB_SUBMSG_INFO_ONEOF3(ltype, structname, unionname, membername) -#define PB_SUBMSG_INFO_ONEOF3(ltype, structname, unionname, membername) PB_SI ## ltype(structname ## _ ## unionname ## _ ## membername ## _MSGTYPE) -#define PB_SUBMSG_INFO_REPEATED(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE) -#define PB_SUBMSG_INFO_FIXARRAY(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE) -#define PB_SI_PB_LTYPE_BOOL(t) -#define PB_SI_PB_LTYPE_BYTES(t) -#define PB_SI_PB_LTYPE_DOUBLE(t) -#define PB_SI_PB_LTYPE_ENUM(t) -#define PB_SI_PB_LTYPE_UENUM(t) -#define PB_SI_PB_LTYPE_FIXED32(t) -#define PB_SI_PB_LTYPE_FIXED64(t) -#define PB_SI_PB_LTYPE_FLOAT(t) -#define PB_SI_PB_LTYPE_INT32(t) -#define PB_SI_PB_LTYPE_INT64(t) -#define PB_SI_PB_LTYPE_MESSAGE(t) PB_SUBMSG_DESCRIPTOR(t) -#define PB_SI_PB_LTYPE_MSG_W_CB(t) PB_SUBMSG_DESCRIPTOR(t) -#define PB_SI_PB_LTYPE_SFIXED32(t) -#define PB_SI_PB_LTYPE_SFIXED64(t) -#define PB_SI_PB_LTYPE_SINT32(t) -#define PB_SI_PB_LTYPE_SINT64(t) -#define PB_SI_PB_LTYPE_STRING(t) -#define PB_SI_PB_LTYPE_UINT32(t) -#define PB_SI_PB_LTYPE_UINT64(t) -#define PB_SI_PB_LTYPE_EXTENSION(t) -#define PB_SI_PB_LTYPE_FIXED_LENGTH_BYTES(t) -#define PB_SUBMSG_DESCRIPTOR(t) &(t ## _msg), - -/* The field descriptors use a variable width format, with width of either - * 1, 2, 4 or 8 of 32-bit words. The two lowest bytes of the first byte always - * encode the descriptor size, 6 lowest bits of field tag number, and 8 bits - * of the field type. - * - * Descriptor size is encoded as 0 = 1 word, 1 = 2 words, 2 = 4 words, 3 = 8 words. - * - * Formats, listed starting with the least significant bit of the first word. - * 1 word: [2-bit len] [6-bit tag] [8-bit type] [8-bit data_offset] [4-bit size_offset] [4-bit data_size] - * - * 2 words: [2-bit len] [6-bit tag] [8-bit type] [12-bit array_size] [4-bit size_offset] - * [16-bit data_offset] [12-bit data_size] [4-bit tag>>6] - * - * 4 words: [2-bit len] [6-bit tag] [8-bit type] [16-bit array_size] - * [8-bit size_offset] [24-bit tag>>6] - * [32-bit data_offset] - * [32-bit data_size] - * - * 8 words: [2-bit len] [6-bit tag] [8-bit type] [16-bit reserved] - * [8-bit size_offset] [24-bit tag>>6] - * [32-bit data_offset] - * [32-bit data_size] - * [32-bit array_size] - * [32-bit reserved] - * [32-bit reserved] - * [32-bit reserved] - */ - -#define PB_FIELDINFO_1(tag, type, data_offset, data_size, size_offset, array_size) \ - (0 | (((tag) << 2) & 0xFF) | ((type) << 8) | (((uint32_t)(data_offset) & 0xFF) << 16) | \ - (((uint32_t)(size_offset) & 0x0F) << 24) | (((uint32_t)(data_size) & 0x0F) << 28)), - -#define PB_FIELDINFO_2(tag, type, data_offset, data_size, size_offset, array_size) \ - (1 | (((tag) << 2) & 0xFF) | ((type) << 8) | (((uint32_t)(array_size) & 0xFFF) << 16) | (((uint32_t)(size_offset) & 0x0F) << 28)), \ - (((uint32_t)(data_offset) & 0xFFFF) | (((uint32_t)(data_size) & 0xFFF) << 16) | (((uint32_t)(tag) & 0x3c0) << 22)), - -#define PB_FIELDINFO_4(tag, type, data_offset, data_size, size_offset, array_size) \ - (2 | (((tag) << 2) & 0xFF) | ((type) << 8) | (((uint32_t)(array_size) & 0xFFFF) << 16)), \ - ((uint32_t)(int_least8_t)(size_offset) | (((uint32_t)(tag) << 2) & 0xFFFFFF00)), \ - (data_offset), (data_size), - -#define PB_FIELDINFO_8(tag, type, data_offset, data_size, size_offset, array_size) \ - (3 | (((tag) << 2) & 0xFF) | ((type) << 8)), \ - ((uint32_t)(int_least8_t)(size_offset) | (((uint32_t)(tag) << 2) & 0xFFFFFF00)), \ - (data_offset), (data_size), (array_size), 0, 0, 0, - -/* These assertions verify that the field information fits in the allocated space. - * The generator tries to automatically determine the correct width that can fit all - * data associated with a message. These asserts will fail only if there has been a - * problem in the automatic logic - this may be worth reporting as a bug. As a workaround, - * you can increase the descriptor width by defining PB_FIELDINFO_WIDTH or by setting - * descriptorsize option in .options file. - */ -#define PB_FITS(value,bits) ((uint32_t)(value) < ((uint32_t)1<2GB messages with nanopb anyway. - */ -#define PB_FIELDINFO_ASSERT_4(tag, type, data_offset, data_size, size_offset, array_size) \ - PB_STATIC_ASSERT(PB_FITS(tag,30) && PB_FITS(data_offset,31) && PB_FITS(size_offset,8) && PB_FITS(data_size,31) && PB_FITS(array_size,16), FIELDINFO_DOES_NOT_FIT_width4_field ## tag) - -#define PB_FIELDINFO_ASSERT_8(tag, type, data_offset, data_size, size_offset, array_size) \ - PB_STATIC_ASSERT(PB_FITS(tag,30) && PB_FITS(data_offset,31) && PB_FITS(size_offset,8) && PB_FITS(data_size,31) && PB_FITS(array_size,31), FIELDINFO_DOES_NOT_FIT_width8_field ## tag) -#endif - - -/* Automatic picking of FIELDINFO width: - * Uses width 1 when possible, otherwise resorts to width 2. - * This is used when PB_BIND() is called with "AUTO" as the argument. - * The generator will give explicit size argument when it knows that a message - * structure grows beyond 1-word format limits. - */ -#define PB_FIELDINFO_WIDTH_AUTO(atype, htype, ltype) PB_FI_WIDTH ## atype(htype, ltype) -#define PB_FI_WIDTH_PB_ATYPE_STATIC(htype, ltype) PB_FI_WIDTH ## htype(ltype) -#define PB_FI_WIDTH_PB_ATYPE_POINTER(htype, ltype) PB_FI_WIDTH ## htype(ltype) -#define PB_FI_WIDTH_PB_ATYPE_CALLBACK(htype, ltype) 2 -#define PB_FI_WIDTH_PB_HTYPE_REQUIRED(ltype) PB_FI_WIDTH ## ltype -#define PB_FI_WIDTH_PB_HTYPE_SINGULAR(ltype) PB_FI_WIDTH ## ltype -#define PB_FI_WIDTH_PB_HTYPE_OPTIONAL(ltype) PB_FI_WIDTH ## ltype -#define PB_FI_WIDTH_PB_HTYPE_ONEOF(ltype) PB_FI_WIDTH ## ltype -#define PB_FI_WIDTH_PB_HTYPE_REPEATED(ltype) 2 -#define PB_FI_WIDTH_PB_HTYPE_FIXARRAY(ltype) 2 -#define PB_FI_WIDTH_PB_LTYPE_BOOL 1 -#define PB_FI_WIDTH_PB_LTYPE_BYTES 2 -#define PB_FI_WIDTH_PB_LTYPE_DOUBLE 1 -#define PB_FI_WIDTH_PB_LTYPE_ENUM 1 -#define PB_FI_WIDTH_PB_LTYPE_UENUM 1 -#define PB_FI_WIDTH_PB_LTYPE_FIXED32 1 -#define PB_FI_WIDTH_PB_LTYPE_FIXED64 1 -#define PB_FI_WIDTH_PB_LTYPE_FLOAT 1 -#define PB_FI_WIDTH_PB_LTYPE_INT32 1 -#define PB_FI_WIDTH_PB_LTYPE_INT64 1 -#define PB_FI_WIDTH_PB_LTYPE_MESSAGE 2 -#define PB_FI_WIDTH_PB_LTYPE_MSG_W_CB 2 -#define PB_FI_WIDTH_PB_LTYPE_SFIXED32 1 -#define PB_FI_WIDTH_PB_LTYPE_SFIXED64 1 -#define PB_FI_WIDTH_PB_LTYPE_SINT32 1 -#define PB_FI_WIDTH_PB_LTYPE_SINT64 1 -#define PB_FI_WIDTH_PB_LTYPE_STRING 2 -#define PB_FI_WIDTH_PB_LTYPE_UINT32 1 -#define PB_FI_WIDTH_PB_LTYPE_UINT64 1 -#define PB_FI_WIDTH_PB_LTYPE_EXTENSION 1 -#define PB_FI_WIDTH_PB_LTYPE_FIXED_LENGTH_BYTES 2 - -/* The mapping from protobuf types to LTYPEs is done using these macros. */ -#define PB_LTYPE_MAP_BOOL PB_LTYPE_BOOL -#define PB_LTYPE_MAP_BYTES PB_LTYPE_BYTES -#define PB_LTYPE_MAP_DOUBLE PB_LTYPE_FIXED64 -#define PB_LTYPE_MAP_ENUM PB_LTYPE_VARINT -#define PB_LTYPE_MAP_UENUM PB_LTYPE_UVARINT -#define PB_LTYPE_MAP_FIXED32 PB_LTYPE_FIXED32 -#define PB_LTYPE_MAP_FIXED64 PB_LTYPE_FIXED64 -#define PB_LTYPE_MAP_FLOAT PB_LTYPE_FIXED32 -#define PB_LTYPE_MAP_INT32 PB_LTYPE_VARINT -#define PB_LTYPE_MAP_INT64 PB_LTYPE_VARINT -#define PB_LTYPE_MAP_MESSAGE PB_LTYPE_SUBMESSAGE -#define PB_LTYPE_MAP_MSG_W_CB PB_LTYPE_SUBMSG_W_CB -#define PB_LTYPE_MAP_SFIXED32 PB_LTYPE_FIXED32 -#define PB_LTYPE_MAP_SFIXED64 PB_LTYPE_FIXED64 -#define PB_LTYPE_MAP_SINT32 PB_LTYPE_SVARINT -#define PB_LTYPE_MAP_SINT64 PB_LTYPE_SVARINT -#define PB_LTYPE_MAP_STRING PB_LTYPE_STRING -#define PB_LTYPE_MAP_UINT32 PB_LTYPE_UVARINT -#define PB_LTYPE_MAP_UINT64 PB_LTYPE_UVARINT -#define PB_LTYPE_MAP_EXTENSION PB_LTYPE_EXTENSION -#define PB_LTYPE_MAP_FIXED_LENGTH_BYTES PB_LTYPE_FIXED_LENGTH_BYTES - -/* These macros are used for giving out error messages. - * They are mostly a debugging aid; the main error information - * is the true/false return value from functions. - * Some code space can be saved by disabling the error - * messages if not used. - * - * PB_SET_ERROR() sets the error message if none has been set yet. - * msg must be a constant string literal. - * PB_GET_ERROR() always returns a pointer to a string. - * PB_RETURN_ERROR() sets the error and returns false from current - * function. - */ -#ifdef PB_NO_ERRMSG -#define PB_SET_ERROR(stream, msg) PB_UNUSED(stream) -#define PB_GET_ERROR(stream) "(errmsg disabled)" -#else -#define PB_SET_ERROR(stream, msg) (stream->errmsg = (stream)->errmsg ? (stream)->errmsg : (msg)) -#define PB_GET_ERROR(stream) ((stream)->errmsg ? (stream)->errmsg : "(none)") -#endif - -#define PB_RETURN_ERROR(stream, msg) return PB_SET_ERROR(stream, msg), false - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#ifdef __cplusplus -#if __cplusplus >= 201103L -#define PB_CONSTEXPR constexpr -#else // __cplusplus >= 201103L -#define PB_CONSTEXPR -#endif // __cplusplus >= 201103L - -#if __cplusplus >= 201703L -#define PB_INLINE_CONSTEXPR inline constexpr -#else // __cplusplus >= 201703L -#define PB_INLINE_CONSTEXPR PB_CONSTEXPR -#endif // __cplusplus >= 201703L - -extern "C++" -{ -namespace nanopb { -// Each type will be partially specialized by the generator. -template struct MessageDescriptor; -} // namespace nanopb -} -#endif /* __cplusplus */ - -#endif diff --git a/src/network/pb_common.c b/src/network/pb_common.c deleted file mode 100644 index 6aee76b1efa..00000000000 --- a/src/network/pb_common.c +++ /dev/null @@ -1,388 +0,0 @@ -/* pb_common.c: Common support functions for pb_encode.c and pb_decode.c. - * - * 2014 Petteri Aimonen - */ - -#include "pb_common.h" - -static bool load_descriptor_values(pb_field_iter_t *iter) -{ - uint32_t word0; - uint32_t data_offset; - int_least8_t size_offset; - - if (iter->index >= iter->descriptor->field_count) - return false; - - word0 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]); - iter->type = (pb_type_t)((word0 >> 8) & 0xFF); - - switch(word0 & 3) - { - case 0: { - /* 1-word format */ - iter->array_size = 1; - iter->tag = (pb_size_t)((word0 >> 2) & 0x3F); - size_offset = (int_least8_t)((word0 >> 24) & 0x0F); - data_offset = (word0 >> 16) & 0xFF; - iter->data_size = (pb_size_t)((word0 >> 28) & 0x0F); - break; - } - - case 1: { - /* 2-word format */ - uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]); - - iter->array_size = (pb_size_t)((word0 >> 16) & 0x0FFF); - iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 28) << 6)); - size_offset = (int_least8_t)((word0 >> 28) & 0x0F); - data_offset = word1 & 0xFFFF; - iter->data_size = (pb_size_t)((word1 >> 16) & 0x0FFF); - break; - } - - case 2: { - /* 4-word format */ - uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]); - uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]); - uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]); - - iter->array_size = (pb_size_t)(word0 >> 16); - iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 8) << 6)); - size_offset = (int_least8_t)(word1 & 0xFF); - data_offset = word2; - iter->data_size = (pb_size_t)word3; - break; - } - - default: { - /* 8-word format */ - uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]); - uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]); - uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]); - uint32_t word4 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 4]); - - iter->array_size = (pb_size_t)word4; - iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 8) << 6)); - size_offset = (int_least8_t)(word1 & 0xFF); - data_offset = word2; - iter->data_size = (pb_size_t)word3; - break; - } - } - - if (!iter->message) - { - /* Avoid doing arithmetic on null pointers, it is undefined */ - iter->pField = NULL; - iter->pSize = NULL; - } - else - { - iter->pField = (char*)iter->message + data_offset; - - if (size_offset) - { - iter->pSize = (char*)iter->pField - size_offset; - } - else if (PB_HTYPE(iter->type) == PB_HTYPE_REPEATED && - (PB_ATYPE(iter->type) == PB_ATYPE_STATIC || - PB_ATYPE(iter->type) == PB_ATYPE_POINTER)) - { - /* Fixed count array */ - iter->pSize = &iter->array_size; - } - else - { - iter->pSize = NULL; - } - - if (PB_ATYPE(iter->type) == PB_ATYPE_POINTER && iter->pField != NULL) - { - iter->pData = *(void**)iter->pField; - } - else - { - iter->pData = iter->pField; - } - } - - if (PB_LTYPE_IS_SUBMSG(iter->type)) - { - iter->submsg_desc = iter->descriptor->submsg_info[iter->submessage_index]; - } - else - { - iter->submsg_desc = NULL; - } - - return true; -} - -static void advance_iterator(pb_field_iter_t *iter) -{ - iter->index++; - - if (iter->index >= iter->descriptor->field_count) - { - /* Restart */ - iter->index = 0; - iter->field_info_index = 0; - iter->submessage_index = 0; - iter->required_field_index = 0; - } - else - { - /* Increment indexes based on previous field type. - * All field info formats have the following fields: - * - lowest 2 bits tell the amount of words in the descriptor (2^n words) - * - bits 2..7 give the lowest bits of tag number. - * - bits 8..15 give the field type. - */ - uint32_t prev_descriptor = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]); - pb_type_t prev_type = (prev_descriptor >> 8) & 0xFF; - pb_size_t descriptor_len = (pb_size_t)(1 << (prev_descriptor & 3)); - - /* Add to fields. - * The cast to pb_size_t is needed to avoid -Wconversion warning. - * Because the data is is constants from generator, there is no danger of overflow. - */ - iter->field_info_index = (pb_size_t)(iter->field_info_index + descriptor_len); - iter->required_field_index = (pb_size_t)(iter->required_field_index + (PB_HTYPE(prev_type) == PB_HTYPE_REQUIRED)); - iter->submessage_index = (pb_size_t)(iter->submessage_index + PB_LTYPE_IS_SUBMSG(prev_type)); - } -} - -bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_msgdesc_t *desc, void *message) -{ - memset(iter, 0, sizeof(*iter)); - - iter->descriptor = desc; - iter->message = message; - - return load_descriptor_values(iter); -} - -bool pb_field_iter_begin_extension(pb_field_iter_t *iter, pb_extension_t *extension) -{ - const pb_msgdesc_t *msg = (const pb_msgdesc_t*)extension->type->arg; - bool status; - - uint32_t word0 = PB_PROGMEM_READU32(msg->field_info[0]); - if (PB_ATYPE(word0 >> 8) == PB_ATYPE_POINTER) - { - /* For pointer extensions, the pointer is stored directly - * in the extension structure. This avoids having an extra - * indirection. */ - status = pb_field_iter_begin(iter, msg, &extension->dest); - } - else - { - status = pb_field_iter_begin(iter, msg, extension->dest); - } - - iter->pSize = &extension->found; - return status; -} - -bool pb_field_iter_next(pb_field_iter_t *iter) -{ - advance_iterator(iter); - (void)load_descriptor_values(iter); - return iter->index != 0; -} - -bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag) -{ - if (iter->tag == tag) - { - return true; /* Nothing to do, correct field already. */ - } - else if (tag > iter->descriptor->largest_tag) - { - return false; - } - else - { - pb_size_t start = iter->index; - uint32_t fieldinfo; - - if (tag < iter->tag) - { - /* Fields are in tag number order, so we know that tag is between - * 0 and our start position. Setting index to end forces - * advance_iterator() call below to restart from beginning. */ - iter->index = iter->descriptor->field_count; - } - - do - { - /* Advance iterator but don't load values yet */ - advance_iterator(iter); - - /* Do fast check for tag number match */ - fieldinfo = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]); - - if (((fieldinfo >> 2) & 0x3F) == (tag & 0x3F)) - { - /* Good candidate, check further */ - (void)load_descriptor_values(iter); - - if (iter->tag == tag && - PB_LTYPE(iter->type) != PB_LTYPE_EXTENSION) - { - /* Found it */ - return true; - } - } - } while (iter->index != start); - - /* Searched all the way back to start, and found nothing. */ - (void)load_descriptor_values(iter); - return false; - } -} - -bool pb_field_iter_find_extension(pb_field_iter_t *iter) -{ - if (PB_LTYPE(iter->type) == PB_LTYPE_EXTENSION) - { - return true; - } - else - { - pb_size_t start = iter->index; - uint32_t fieldinfo; - - do - { - /* Advance iterator but don't load values yet */ - advance_iterator(iter); - - /* Do fast check for field type */ - fieldinfo = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]); - - if (PB_LTYPE((fieldinfo >> 8) & 0xFF) == PB_LTYPE_EXTENSION) - { - return load_descriptor_values(iter); - } - } while (iter->index != start); - - /* Searched all the way back to start, and found nothing. */ - (void)load_descriptor_values(iter); - return false; - } -} - -static void *pb_const_cast(const void *p) -{ - /* Note: this casts away const, in order to use the common field iterator - * logic for both encoding and decoding. The cast is done using union - * to avoid spurious compiler warnings. */ - union { - void *p1; - const void *p2; - } t; - t.p2 = p; - return t.p1; -} - -bool pb_field_iter_begin_const(pb_field_iter_t *iter, const pb_msgdesc_t *desc, const void *message) -{ - return pb_field_iter_begin(iter, desc, pb_const_cast(message)); -} - -bool pb_field_iter_begin_extension_const(pb_field_iter_t *iter, const pb_extension_t *extension) -{ - return pb_field_iter_begin_extension(iter, (pb_extension_t*)pb_const_cast(extension)); -} - -bool pb_default_field_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_t *field) -{ - if (field->data_size == sizeof(pb_callback_t)) - { - pb_callback_t *pCallback = (pb_callback_t*)field->pData; - - if (pCallback != NULL) - { - if (istream != NULL && pCallback->funcs.decode != NULL) - { - return pCallback->funcs.decode(istream, field, &pCallback->arg); - } - - if (ostream != NULL && pCallback->funcs.encode != NULL) - { - return pCallback->funcs.encode(ostream, field, &pCallback->arg); - } - } - } - - return true; /* Success, but didn't do anything */ - -} - -#ifdef PB_VALIDATE_UTF8 - -/* This function checks whether a string is valid UTF-8 text. - * - * Algorithm is adapted from https://www.cl.cam.ac.uk/~mgk25/ucs/utf8_check.c - * Original copyright: Markus Kuhn 2005-03-30 - * Licensed under "Short code license", which allows use under MIT license or - * any compatible with it. - */ - -bool pb_validate_utf8(const char *str) -{ - const pb_byte_t *s = (const pb_byte_t*)str; - while (*s) - { - if (*s < 0x80) - { - /* 0xxxxxxx */ - s++; - } - else if ((s[0] & 0xe0) == 0xc0) - { - /* 110XXXXx 10xxxxxx */ - if ((s[1] & 0xc0) != 0x80 || - (s[0] & 0xfe) == 0xc0) /* overlong? */ - return false; - else - s += 2; - } - else if ((s[0] & 0xf0) == 0xe0) - { - /* 1110XXXX 10Xxxxxx 10xxxxxx */ - if ((s[1] & 0xc0) != 0x80 || - (s[2] & 0xc0) != 0x80 || - (s[0] == 0xe0 && (s[1] & 0xe0) == 0x80) || /* overlong? */ - (s[0] == 0xed && (s[1] & 0xe0) == 0xa0) || /* surrogate? */ - (s[0] == 0xef && s[1] == 0xbf && - (s[2] & 0xfe) == 0xbe)) /* U+FFFE or U+FFFF? */ - return false; - else - s += 3; - } - else if ((s[0] & 0xf8) == 0xf0) - { - /* 11110XXX 10XXxxxx 10xxxxxx 10xxxxxx */ - if ((s[1] & 0xc0) != 0x80 || - (s[2] & 0xc0) != 0x80 || - (s[3] & 0xc0) != 0x80 || - (s[0] == 0xf0 && (s[1] & 0xf0) == 0x80) || /* overlong? */ - (s[0] == 0xf4 && s[1] > 0x8f) || s[0] > 0xf4) /* > U+10FFFF? */ - return false; - else - s += 4; - } - else - { - return false; - } - } - - return true; -} - -#endif - diff --git a/src/network/pb_common.h b/src/network/pb_common.h deleted file mode 100644 index 58aa90f76d5..00000000000 --- a/src/network/pb_common.h +++ /dev/null @@ -1,49 +0,0 @@ -/* pb_common.h: Common support functions for pb_encode.c and pb_decode.c. - * These functions are rarely needed by applications directly. - */ - -#ifndef PB_COMMON_H_INCLUDED -#define PB_COMMON_H_INCLUDED - -#include "pb.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Initialize the field iterator structure to beginning. - * Returns false if the message type is empty. */ -bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_msgdesc_t *desc, void *message); - -/* Get a field iterator for extension field. */ -bool pb_field_iter_begin_extension(pb_field_iter_t *iter, pb_extension_t *extension); - -/* Same as pb_field_iter_begin(), but for const message pointer. - * Note that the pointers in pb_field_iter_t will be non-const but shouldn't - * be written to when using these functions. */ -bool pb_field_iter_begin_const(pb_field_iter_t *iter, const pb_msgdesc_t *desc, const void *message); -bool pb_field_iter_begin_extension_const(pb_field_iter_t *iter, const pb_extension_t *extension); - -/* Advance the iterator to the next field. - * Returns false when the iterator wraps back to the first field. */ -bool pb_field_iter_next(pb_field_iter_t *iter); - -/* Advance the iterator until it points at a field with the given tag. - * Returns false if no such field exists. */ -bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag); - -/* Find a field with type PB_LTYPE_EXTENSION, or return false if not found. - * There can be only one extension range field per message. */ -bool pb_field_iter_find_extension(pb_field_iter_t *iter); - -#ifdef PB_VALIDATE_UTF8 -/* Validate UTF-8 text string */ -bool pb_validate_utf8(const char *s); -#endif - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif - diff --git a/src/network/pb_decode.c b/src/network/pb_decode.c deleted file mode 100644 index 788998eb962..00000000000 --- a/src/network/pb_decode.c +++ /dev/null @@ -1,1727 +0,0 @@ -/* pb_decode.c -- decode a protobuf using minimal resources - * - * 2011 Petteri Aimonen - */ - -/* Use the GCC warn_unused_result attribute to check that all return values - * are propagated correctly. On other compilers and gcc before 3.4.0 just - * ignore the annotation. - */ -#if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) - #define checkreturn -#else - #define checkreturn __attribute__((warn_unused_result)) -#endif - -#include "pb.h" -#include "pb_decode.h" -#include "pb_common.h" - -/************************************** - * Declarations internal to this file * - **************************************/ - -static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count); -static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *dest, bool *eof); -static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size); -static bool checkreturn decode_basic_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field); -static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field); -static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field); -static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field); -static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field); -static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type); -static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_extension_t *extension); -static bool pb_field_set_to_default(pb_field_iter_t *field); -static bool pb_message_set_to_defaults(pb_field_iter_t *iter); -static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_iter_t *field); -static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_iter_t *field); -static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_iter_t *field); -static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_iter_t *field); -static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_iter_t *field); -static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_iter_t *field); -static bool checkreturn pb_skip_varint(pb_istream_t *stream); -static bool checkreturn pb_skip_string(pb_istream_t *stream); - -#ifdef PB_ENABLE_MALLOC -static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size); -static void initialize_pointer_field(void *pItem, pb_field_iter_t *field); -static bool checkreturn pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *field); -static void pb_release_single_field(pb_field_iter_t *field); -#endif - -#ifdef PB_WITHOUT_64BIT -#define pb_int64_t int32_t -#define pb_uint64_t uint32_t -#else -#define pb_int64_t int64_t -#define pb_uint64_t uint64_t -#endif - -typedef struct { - uint32_t bitfield[(PB_MAX_REQUIRED_FIELDS + 31) / 32]; -} pb_fields_seen_t; - -/******************************* - * pb_istream_t implementation * - *******************************/ - -static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count) -{ - const pb_byte_t *source = (const pb_byte_t*)stream->state; - stream->state = (pb_byte_t*)stream->state + count; - - if (buf != NULL) - { - memcpy(buf, source, count * sizeof(pb_byte_t)); - } - - return true; -} - -bool checkreturn pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count) -{ - if (count == 0) - return true; - -#ifndef PB_BUFFER_ONLY - if (buf == NULL && stream->callback != buf_read) - { - /* Skip input bytes */ - pb_byte_t tmp[16]; - while (count > 16) - { - if (!pb_read(stream, tmp, 16)) - return false; - - count -= 16; - } - - return pb_read(stream, tmp, count); - } -#endif - - if (stream->bytes_left < count) - PB_RETURN_ERROR(stream, "end-of-stream"); - -#ifndef PB_BUFFER_ONLY - if (!stream->callback(stream, buf, count)) - PB_RETURN_ERROR(stream, "io error"); -#else - if (!buf_read(stream, buf, count)) - return false; -#endif - - if (stream->bytes_left < count) - stream->bytes_left = 0; - else - stream->bytes_left -= count; - - return true; -} - -/* Read a single byte from input stream. buf may not be NULL. - * This is an optimization for the varint decoding. */ -static bool checkreturn pb_readbyte(pb_istream_t *stream, pb_byte_t *buf) -{ - if (stream->bytes_left == 0) - PB_RETURN_ERROR(stream, "end-of-stream"); - -#ifndef PB_BUFFER_ONLY - if (!stream->callback(stream, buf, 1)) - PB_RETURN_ERROR(stream, "io error"); -#else - *buf = *(const pb_byte_t*)stream->state; - stream->state = (pb_byte_t*)stream->state + 1; -#endif - - stream->bytes_left--; - - return true; -} - -pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t msglen) -{ - pb_istream_t stream; - /* Cast away the const from buf without a compiler error. We are - * careful to use it only in a const manner in the callbacks. - */ - union { - void *state; - const void *c_state; - } state; -#ifdef PB_BUFFER_ONLY - stream.callback = NULL; -#else - stream.callback = &buf_read; -#endif - state.c_state = buf; - stream.state = state.state; - stream.bytes_left = msglen; -#ifndef PB_NO_ERRMSG - stream.errmsg = NULL; -#endif - return stream; -} - -/******************** - * Helper functions * - ********************/ - -static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *dest, bool *eof) -{ - pb_byte_t byte; - uint32_t result; - - if (!pb_readbyte(stream, &byte)) - { - if (stream->bytes_left == 0) - { - if (eof) - { - *eof = true; - } - } - - return false; - } - - if ((byte & 0x80) == 0) - { - /* Quick case, 1 byte value */ - result = byte; - } - else - { - /* Multibyte case */ - uint_fast8_t bitpos = 7; - result = byte & 0x7F; - - do - { - if (!pb_readbyte(stream, &byte)) - return false; - - if (bitpos >= 32) - { - /* Note: The varint could have trailing 0x80 bytes, or 0xFF for negative. */ - pb_byte_t sign_extension = (bitpos < 63) ? 0xFF : 0x01; - bool valid_extension = ((byte & 0x7F) == 0x00 || - ((result >> 31) != 0 && byte == sign_extension)); - - if (bitpos >= 64 || !valid_extension) - { - PB_RETURN_ERROR(stream, "varint overflow"); - } - } - else if (bitpos == 28) - { - if ((byte & 0x70) != 0 && (byte & 0x78) != 0x78) - { - PB_RETURN_ERROR(stream, "varint overflow"); - } - result |= (uint32_t)(byte & 0x0F) << bitpos; - } - else - { - result |= (uint32_t)(byte & 0x7F) << bitpos; - } - bitpos = (uint_fast8_t)(bitpos + 7); - } while (byte & 0x80); - } - - *dest = result; - return true; -} - -bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest) -{ - return pb_decode_varint32_eof(stream, dest, NULL); -} - -#ifndef PB_WITHOUT_64BIT -bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest) -{ - pb_byte_t byte; - uint_fast8_t bitpos = 0; - uint64_t result = 0; - - do - { - if (!pb_readbyte(stream, &byte)) - return false; - - if (bitpos >= 63 && (byte & 0xFE) != 0) - PB_RETURN_ERROR(stream, "varint overflow"); - - result |= (uint64_t)(byte & 0x7F) << bitpos; - bitpos = (uint_fast8_t)(bitpos + 7); - } while (byte & 0x80); - - *dest = result; - return true; -} -#endif - -bool checkreturn pb_skip_varint(pb_istream_t *stream) -{ - pb_byte_t byte; - do - { - if (!pb_read(stream, &byte, 1)) - return false; - } while (byte & 0x80); - return true; -} - -bool checkreturn pb_skip_string(pb_istream_t *stream) -{ - uint32_t length; - if (!pb_decode_varint32(stream, &length)) - return false; - - if ((size_t)length != length) - { - PB_RETURN_ERROR(stream, "size too large"); - } - - return pb_read(stream, NULL, (size_t)length); -} - -bool checkreturn pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof) -{ - uint32_t temp; - *eof = false; - *wire_type = (pb_wire_type_t) 0; - *tag = 0; - - if (!pb_decode_varint32_eof(stream, &temp, eof)) - { - return false; - } - - *tag = temp >> 3; - *wire_type = (pb_wire_type_t)(temp & 7); - return true; -} - -bool checkreturn pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type) -{ - switch (wire_type) - { - case PB_WT_VARINT: return pb_skip_varint(stream); - case PB_WT_64BIT: return pb_read(stream, NULL, 8); - case PB_WT_STRING: return pb_skip_string(stream); - case PB_WT_32BIT: return pb_read(stream, NULL, 4); - default: PB_RETURN_ERROR(stream, "invalid wire_type"); - } -} - -/* Read a raw value to buffer, for the purpose of passing it to callback as - * a substream. Size is maximum size on call, and actual size on return. - */ -static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size) -{ - size_t max_size = *size; - switch (wire_type) - { - case PB_WT_VARINT: - *size = 0; - do - { - (*size)++; - if (*size > max_size) - PB_RETURN_ERROR(stream, "varint overflow"); - - if (!pb_read(stream, buf, 1)) - return false; - } while (*buf++ & 0x80); - return true; - - case PB_WT_64BIT: - *size = 8; - return pb_read(stream, buf, 8); - - case PB_WT_32BIT: - *size = 4; - return pb_read(stream, buf, 4); - - case PB_WT_STRING: - /* Calling read_raw_value with a PB_WT_STRING is an error. - * Explicitly handle this case and fallthrough to default to avoid - * compiler warnings. - */ - - default: PB_RETURN_ERROR(stream, "invalid wire_type"); - } -} - -/* Decode string length from stream and return a substream with limited length. - * Remember to close the substream using pb_close_string_substream(). - */ -bool checkreturn pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream) -{ - uint32_t size; - if (!pb_decode_varint32(stream, &size)) - return false; - - *substream = *stream; - if (substream->bytes_left < size) - PB_RETURN_ERROR(stream, "parent stream too short"); - - substream->bytes_left = (size_t)size; - stream->bytes_left -= (size_t)size; - return true; -} - -bool checkreturn pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream) -{ - if (substream->bytes_left) { - if (!pb_read(substream, NULL, substream->bytes_left)) - return false; - } - - stream->state = substream->state; - -#ifndef PB_NO_ERRMSG - stream->errmsg = substream->errmsg; -#endif - return true; -} - -/************************* - * Decode a single field * - *************************/ - -static bool checkreturn decode_basic_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field) -{ - switch (PB_LTYPE(field->type)) - { - case PB_LTYPE_BOOL: - if (wire_type != PB_WT_VARINT && wire_type != PB_WT_PACKED) - PB_RETURN_ERROR(stream, "wrong wire type"); - - return pb_dec_bool(stream, field); - - case PB_LTYPE_VARINT: - case PB_LTYPE_UVARINT: - case PB_LTYPE_SVARINT: - if (wire_type != PB_WT_VARINT && wire_type != PB_WT_PACKED) - PB_RETURN_ERROR(stream, "wrong wire type"); - - return pb_dec_varint(stream, field); - - case PB_LTYPE_FIXED32: - if (wire_type != PB_WT_32BIT && wire_type != PB_WT_PACKED) - PB_RETURN_ERROR(stream, "wrong wire type"); - - return pb_decode_fixed32(stream, field->pData); - - case PB_LTYPE_FIXED64: - if (wire_type != PB_WT_64BIT && wire_type != PB_WT_PACKED) - PB_RETURN_ERROR(stream, "wrong wire type"); - -#ifdef PB_CONVERT_DOUBLE_FLOAT - if (field->data_size == sizeof(float)) - { - return pb_decode_double_as_float(stream, (float*)field->pData); - } -#endif - -#ifdef PB_WITHOUT_64BIT - PB_RETURN_ERROR(stream, "invalid data_size"); -#else - return pb_decode_fixed64(stream, field->pData); -#endif - - case PB_LTYPE_BYTES: - if (wire_type != PB_WT_STRING) - PB_RETURN_ERROR(stream, "wrong wire type"); - - return pb_dec_bytes(stream, field); - - case PB_LTYPE_STRING: - if (wire_type != PB_WT_STRING) - PB_RETURN_ERROR(stream, "wrong wire type"); - - return pb_dec_string(stream, field); - - case PB_LTYPE_SUBMESSAGE: - case PB_LTYPE_SUBMSG_W_CB: - if (wire_type != PB_WT_STRING) - PB_RETURN_ERROR(stream, "wrong wire type"); - - return pb_dec_submessage(stream, field); - - case PB_LTYPE_FIXED_LENGTH_BYTES: - if (wire_type != PB_WT_STRING) - PB_RETURN_ERROR(stream, "wrong wire type"); - - return pb_dec_fixed_length_bytes(stream, field); - - default: - PB_RETURN_ERROR(stream, "invalid field type"); - } -} - -static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field) -{ - switch (PB_HTYPE(field->type)) - { - case PB_HTYPE_REQUIRED: - return decode_basic_field(stream, wire_type, field); - - case PB_HTYPE_OPTIONAL: - if (field->pSize != NULL) - *(bool*)field->pSize = true; - return decode_basic_field(stream, wire_type, field); - - case PB_HTYPE_REPEATED: - if (wire_type == PB_WT_STRING - && PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE) - { - /* Packed array */ - bool status = true; - pb_istream_t substream; - pb_size_t *size = (pb_size_t*)field->pSize; - field->pData = (char*)field->pField + field->data_size * (*size); - - if (!pb_make_string_substream(stream, &substream)) - return false; - - while (substream.bytes_left > 0 && *size < field->array_size) - { - if (!decode_basic_field(&substream, PB_WT_PACKED, field)) - { - status = false; - break; - } - (*size)++; - field->pData = (char*)field->pData + field->data_size; - } - - if (substream.bytes_left != 0) - PB_RETURN_ERROR(stream, "array overflow"); - if (!pb_close_string_substream(stream, &substream)) - return false; - - return status; - } - else - { - /* Repeated field */ - pb_size_t *size = (pb_size_t*)field->pSize; - field->pData = (char*)field->pField + field->data_size * (*size); - - if ((*size)++ >= field->array_size) - PB_RETURN_ERROR(stream, "array overflow"); - - return decode_basic_field(stream, wire_type, field); - } - - case PB_HTYPE_ONEOF: - if (PB_LTYPE_IS_SUBMSG(field->type) && - *(pb_size_t*)field->pSize != field->tag) - { - /* We memset to zero so that any callbacks are set to NULL. - * This is because the callbacks might otherwise have values - * from some other union field. - * If callbacks are needed inside oneof field, use .proto - * option submsg_callback to have a separate callback function - * that can set the fields before submessage is decoded. - * pb_dec_submessage() will set any default values. */ - memset(field->pData, 0, (size_t)field->data_size); - - /* Set default values for the submessage fields. */ - if (field->submsg_desc->default_value != NULL || - field->submsg_desc->field_callback != NULL || - field->submsg_desc->submsg_info[0] != NULL) - { - pb_field_iter_t submsg_iter; - if (pb_field_iter_begin(&submsg_iter, field->submsg_desc, field->pData)) - { - if (!pb_message_set_to_defaults(&submsg_iter)) - PB_RETURN_ERROR(stream, "failed to set defaults"); - } - } - } - *(pb_size_t*)field->pSize = field->tag; - - return decode_basic_field(stream, wire_type, field); - - default: - PB_RETURN_ERROR(stream, "invalid field type"); - } -} - -#ifdef PB_ENABLE_MALLOC -/* Allocate storage for the field and store the pointer at iter->pData. - * array_size is the number of entries to reserve in an array. - * Zero size is not allowed, use pb_free() for releasing. - */ -static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size) -{ - void *ptr = *(void**)pData; - - if (data_size == 0 || array_size == 0) - PB_RETURN_ERROR(stream, "invalid size"); - -#ifdef __AVR__ - /* Workaround for AVR libc bug 53284: http://savannah.nongnu.org/bugs/?53284 - * Realloc to size of 1 byte can cause corruption of the malloc structures. - */ - if (data_size == 1 && array_size == 1) - { - data_size = 2; - } -#endif - - /* Check for multiplication overflows. - * This code avoids the costly division if the sizes are small enough. - * Multiplication is safe as long as only half of bits are set - * in either multiplicand. - */ - { - const size_t check_limit = (size_t)1 << (sizeof(size_t) * 4); - if (data_size >= check_limit || array_size >= check_limit) - { - const size_t size_max = (size_t)-1; - if (size_max / array_size < data_size) - { - PB_RETURN_ERROR(stream, "size too large"); - } - } - } - - /* Allocate new or expand previous allocation */ - /* Note: on failure the old pointer will remain in the structure, - * the message must be freed by caller also on error return. */ - ptr = pb_realloc(ptr, array_size * data_size); - if (ptr == NULL) - PB_RETURN_ERROR(stream, "realloc failed"); - - *(void**)pData = ptr; - return true; -} - -/* Clear a newly allocated item in case it contains a pointer, or is a submessage. */ -static void initialize_pointer_field(void *pItem, pb_field_iter_t *field) -{ - if (PB_LTYPE(field->type) == PB_LTYPE_STRING || - PB_LTYPE(field->type) == PB_LTYPE_BYTES) - { - *(void**)pItem = NULL; - } - else if (PB_LTYPE_IS_SUBMSG(field->type)) - { - /* We memset to zero so that any callbacks are set to NULL. - * Default values will be set by pb_dec_submessage(). */ - memset(pItem, 0, field->data_size); - } -} -#endif - -static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field) -{ -#ifndef PB_ENABLE_MALLOC - PB_UNUSED(wire_type); - PB_UNUSED(field); - PB_RETURN_ERROR(stream, "no malloc support"); -#else - switch (PB_HTYPE(field->type)) - { - case PB_HTYPE_REQUIRED: - case PB_HTYPE_OPTIONAL: - case PB_HTYPE_ONEOF: - if (PB_LTYPE_IS_SUBMSG(field->type) && *(void**)field->pField != NULL) - { - /* Duplicate field, have to release the old allocation first. */ - /* FIXME: Does this work correctly for oneofs? */ - pb_release_single_field(field); - } - - if (PB_HTYPE(field->type) == PB_HTYPE_ONEOF) - { - *(pb_size_t*)field->pSize = field->tag; - } - - if (PB_LTYPE(field->type) == PB_LTYPE_STRING || - PB_LTYPE(field->type) == PB_LTYPE_BYTES) - { - /* pb_dec_string and pb_dec_bytes handle allocation themselves */ - field->pData = field->pField; - return decode_basic_field(stream, wire_type, field); - } - else - { - if (!allocate_field(stream, field->pField, field->data_size, 1)) - return false; - - field->pData = *(void**)field->pField; - initialize_pointer_field(field->pData, field); - return decode_basic_field(stream, wire_type, field); - } - - case PB_HTYPE_REPEATED: - if (wire_type == PB_WT_STRING - && PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE) - { - /* Packed array, multiple items come in at once. */ - bool status = true; - pb_size_t *size = (pb_size_t*)field->pSize; - size_t allocated_size = *size; - pb_istream_t substream; - - if (!pb_make_string_substream(stream, &substream)) - return false; - - while (substream.bytes_left) - { - if (*size == PB_SIZE_MAX) - { -#ifndef PB_NO_ERRMSG - stream->errmsg = "too many array entries"; -#endif - status = false; - break; - } - - if ((size_t)*size + 1 > allocated_size) - { - /* Allocate more storage. This tries to guess the - * number of remaining entries. Round the division - * upwards. */ - size_t remain = (substream.bytes_left - 1) / field->data_size + 1; - if (remain < PB_SIZE_MAX - allocated_size) - allocated_size += remain; - else - allocated_size += 1; - - if (!allocate_field(&substream, field->pField, field->data_size, allocated_size)) - { - status = false; - break; - } - } - - /* Decode the array entry */ - field->pData = *(char**)field->pField + field->data_size * (*size); - if (field->pData == NULL) - { - /* Shouldn't happen, but satisfies static analyzers */ - status = false; - break; - } - initialize_pointer_field(field->pData, field); - if (!decode_basic_field(&substream, PB_WT_PACKED, field)) - { - status = false; - break; - } - - (*size)++; - } - if (!pb_close_string_substream(stream, &substream)) - return false; - - return status; - } - else - { - /* Normal repeated field, i.e. only one item at a time. */ - pb_size_t *size = (pb_size_t*)field->pSize; - - if (*size == PB_SIZE_MAX) - PB_RETURN_ERROR(stream, "too many array entries"); - - if (!allocate_field(stream, field->pField, field->data_size, (size_t)(*size + 1))) - return false; - - field->pData = *(char**)field->pField + field->data_size * (*size); - (*size)++; - initialize_pointer_field(field->pData, field); - return decode_basic_field(stream, wire_type, field); - } - - default: - PB_RETURN_ERROR(stream, "invalid field type"); - } -#endif -} - -static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field) -{ - if (!field->descriptor->field_callback) - return pb_skip_field(stream, wire_type); - - if (wire_type == PB_WT_STRING) - { - pb_istream_t substream; - size_t prev_bytes_left; - - if (!pb_make_string_substream(stream, &substream)) - return false; - - do - { - prev_bytes_left = substream.bytes_left; - if (!field->descriptor->field_callback(&substream, NULL, field)) - { - PB_SET_ERROR(stream, substream.errmsg ? substream.errmsg : "callback failed"); - return false; - } - } while (substream.bytes_left > 0 && substream.bytes_left < prev_bytes_left); - - if (!pb_close_string_substream(stream, &substream)) - return false; - - return true; - } - else - { - /* Copy the single scalar value to stack. - * This is required so that we can limit the stream length, - * which in turn allows to use same callback for packed and - * not-packed fields. */ - pb_istream_t substream; - pb_byte_t buffer[10]; - size_t size = sizeof(buffer); - - if (!read_raw_value(stream, wire_type, buffer, &size)) - return false; - substream = pb_istream_from_buffer(buffer, size); - - return field->descriptor->field_callback(&substream, NULL, field); - } -} - -static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *field) -{ -#ifdef PB_ENABLE_MALLOC - /* When decoding an oneof field, check if there is old data that must be - * released first. */ - if (PB_HTYPE(field->type) == PB_HTYPE_ONEOF) - { - if (!pb_release_union_field(stream, field)) - return false; - } -#endif - - switch (PB_ATYPE(field->type)) - { - case PB_ATYPE_STATIC: - return decode_static_field(stream, wire_type, field); - - case PB_ATYPE_POINTER: - return decode_pointer_field(stream, wire_type, field); - - case PB_ATYPE_CALLBACK: - return decode_callback_field(stream, wire_type, field); - - default: - PB_RETURN_ERROR(stream, "invalid field type"); - } -} - -/* Default handler for extension fields. Expects to have a pb_msgdesc_t - * pointer in the extension->type->arg field, pointing to a message with - * only one field in it. */ -static bool checkreturn default_extension_decoder(pb_istream_t *stream, - pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type) -{ - pb_field_iter_t iter; - - if (!pb_field_iter_begin_extension(&iter, extension)) - PB_RETURN_ERROR(stream, "invalid extension"); - - if (iter.tag != tag || !iter.message) - return true; - - extension->found = true; - return decode_field(stream, wire_type, &iter); -} - -/* Try to decode an unknown field as an extension field. Tries each extension - * decoder in turn, until one of them handles the field or loop ends. */ -static bool checkreturn decode_extension(pb_istream_t *stream, - uint32_t tag, pb_wire_type_t wire_type, pb_extension_t *extension) -{ - size_t pos = stream->bytes_left; - - while (extension != NULL && pos == stream->bytes_left) - { - bool status; - if (extension->type->decode) - status = extension->type->decode(stream, extension, tag, wire_type); - else - status = default_extension_decoder(stream, extension, tag, wire_type); - - if (!status) - return false; - - extension = extension->next; - } - - return true; -} - -/* Initialize message fields to default values, recursively */ -static bool pb_field_set_to_default(pb_field_iter_t *field) -{ - pb_type_t type; - type = field->type; - - if (PB_LTYPE(type) == PB_LTYPE_EXTENSION) - { - pb_extension_t *ext = *(pb_extension_t* const *)field->pData; - while (ext != NULL) - { - pb_field_iter_t ext_iter; - if (pb_field_iter_begin_extension(&ext_iter, ext)) - { - ext->found = false; - if (!pb_message_set_to_defaults(&ext_iter)) - return false; - } - ext = ext->next; - } - } - else if (PB_ATYPE(type) == PB_ATYPE_STATIC) - { - bool init_data = true; - if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && field->pSize != NULL) - { - /* Set has_field to false. Still initialize the optional field - * itself also. */ - *(bool*)field->pSize = false; - } - else if (PB_HTYPE(type) == PB_HTYPE_REPEATED || - PB_HTYPE(type) == PB_HTYPE_ONEOF) - { - /* REPEATED: Set array count to 0, no need to initialize contents. - ONEOF: Set which_field to 0. */ - *(pb_size_t*)field->pSize = 0; - init_data = false; - } - - if (init_data) - { - if (PB_LTYPE_IS_SUBMSG(field->type) && - (field->submsg_desc->default_value != NULL || - field->submsg_desc->field_callback != NULL || - field->submsg_desc->submsg_info[0] != NULL)) - { - /* Initialize submessage to defaults. - * Only needed if it has default values - * or callback/submessage fields. */ - pb_field_iter_t submsg_iter; - if (pb_field_iter_begin(&submsg_iter, field->submsg_desc, field->pData)) - { - if (!pb_message_set_to_defaults(&submsg_iter)) - return false; - } - } - else - { - /* Initialize to zeros */ - memset(field->pData, 0, (size_t)field->data_size); - } - } - } - else if (PB_ATYPE(type) == PB_ATYPE_POINTER) - { - /* Initialize the pointer to NULL. */ - *(void**)field->pField = NULL; - - /* Initialize array count to 0. */ - if (PB_HTYPE(type) == PB_HTYPE_REPEATED || - PB_HTYPE(type) == PB_HTYPE_ONEOF) - { - *(pb_size_t*)field->pSize = 0; - } - } - else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK) - { - /* Don't overwrite callback */ - } - - return true; -} - -static bool pb_message_set_to_defaults(pb_field_iter_t *iter) -{ - pb_istream_t defstream = PB_ISTREAM_EMPTY; - uint32_t tag = 0; - pb_wire_type_t wire_type = PB_WT_VARINT; - bool eof; - - if (iter->descriptor->default_value) - { - defstream = pb_istream_from_buffer(iter->descriptor->default_value, (size_t)-1); - if (!pb_decode_tag(&defstream, &wire_type, &tag, &eof)) - return false; - } - - do - { - if (!pb_field_set_to_default(iter)) - return false; - - if (tag != 0 && iter->tag == tag) - { - /* We have a default value for this field in the defstream */ - if (!decode_field(&defstream, wire_type, iter)) - return false; - if (!pb_decode_tag(&defstream, &wire_type, &tag, &eof)) - return false; - - if (iter->pSize) - *(bool*)iter->pSize = false; - } - } while (pb_field_iter_next(iter)); - - return true; -} - -/********************* - * Decode all fields * - *********************/ - -static bool checkreturn pb_decode_inner(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct, unsigned int flags) -{ - uint32_t extension_range_start = 0; - pb_extension_t *extensions = NULL; - - /* 'fixed_count_field' and 'fixed_count_size' track position of a repeated fixed - * count field. This can only handle _one_ repeated fixed count field that - * is unpacked and unordered among other (non repeated fixed count) fields. - */ - pb_size_t fixed_count_field = PB_SIZE_MAX; - pb_size_t fixed_count_size = 0; - pb_size_t fixed_count_total_size = 0; - - pb_fields_seen_t fields_seen = {{0, 0}}; - const uint32_t allbits = ~(uint32_t)0; - pb_field_iter_t iter; - - if (pb_field_iter_begin(&iter, fields, dest_struct)) - { - if ((flags & PB_DECODE_NOINIT) == 0) - { - if (!pb_message_set_to_defaults(&iter)) - PB_RETURN_ERROR(stream, "failed to set defaults"); - } - } - - while (stream->bytes_left) - { - uint32_t tag; - pb_wire_type_t wire_type; - bool eof; - - if (!pb_decode_tag(stream, &wire_type, &tag, &eof)) - { - if (eof) - break; - else - return false; - } - - if (tag == 0) - { - if (flags & PB_DECODE_NULLTERMINATED) - { - break; - } - else - { - PB_RETURN_ERROR(stream, "zero tag"); - } - } - - if (!pb_field_iter_find(&iter, tag) || PB_LTYPE(iter.type) == PB_LTYPE_EXTENSION) - { - /* No match found, check if it matches an extension. */ - if (extension_range_start == 0) - { - if (pb_field_iter_find_extension(&iter)) - { - extensions = *(pb_extension_t* const *)iter.pData; - extension_range_start = iter.tag; - } - - if (!extensions) - { - extension_range_start = (uint32_t)-1; - } - } - - if (tag >= extension_range_start) - { - size_t pos = stream->bytes_left; - - if (!decode_extension(stream, tag, wire_type, extensions)) - return false; - - if (pos != stream->bytes_left) - { - /* The field was handled */ - continue; - } - } - - /* No match found, skip data */ - if (!pb_skip_field(stream, wire_type)) - return false; - continue; - } - - /* If a repeated fixed count field was found, get size from - * 'fixed_count_field' as there is no counter contained in the struct. - */ - if (PB_HTYPE(iter.type) == PB_HTYPE_REPEATED && iter.pSize == &iter.array_size) - { - if (fixed_count_field != iter.index) { - /* If the new fixed count field does not match the previous one, - * check that the previous one is NULL or that it finished - * receiving all the expected data. - */ - if (fixed_count_field != PB_SIZE_MAX && - fixed_count_size != fixed_count_total_size) - { - PB_RETURN_ERROR(stream, "wrong size for fixed count field"); - } - - fixed_count_field = iter.index; - fixed_count_size = 0; - fixed_count_total_size = iter.array_size; - } - - iter.pSize = &fixed_count_size; - } - - if (PB_HTYPE(iter.type) == PB_HTYPE_REQUIRED - && iter.required_field_index < PB_MAX_REQUIRED_FIELDS) - { - uint32_t tmp = ((uint32_t)1 << (iter.required_field_index & 31)); - fields_seen.bitfield[iter.required_field_index >> 5] |= tmp; - } - - if (!decode_field(stream, wire_type, &iter)) - return false; - } - - /* Check that all elements of the last decoded fixed count field were present. */ - if (fixed_count_field != PB_SIZE_MAX && - fixed_count_size != fixed_count_total_size) - { - PB_RETURN_ERROR(stream, "wrong size for fixed count field"); - } - - /* Check that all required fields were present. */ - { - pb_size_t req_field_count = iter.descriptor->required_field_count; - - if (req_field_count > 0) - { - pb_size_t i; - - if (req_field_count > PB_MAX_REQUIRED_FIELDS) - req_field_count = PB_MAX_REQUIRED_FIELDS; - - /* Check the whole words */ - for (i = 0; i < (req_field_count >> 5); i++) - { - if (fields_seen.bitfield[i] != allbits) - PB_RETURN_ERROR(stream, "missing required field"); - } - - /* Check the remaining bits (if any) */ - if ((req_field_count & 31) != 0) - { - if (fields_seen.bitfield[req_field_count >> 5] != - (allbits >> (uint_least8_t)(32 - (req_field_count & 31)))) - { - PB_RETURN_ERROR(stream, "missing required field"); - } - } - } - } - - return true; -} - -bool checkreturn pb_decode_ex(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct, unsigned int flags) -{ - bool status; - - if ((flags & PB_DECODE_DELIMITED) == 0) - { - status = pb_decode_inner(stream, fields, dest_struct, flags); - } - else - { - pb_istream_t substream; - if (!pb_make_string_substream(stream, &substream)) - return false; - - status = pb_decode_inner(&substream, fields, dest_struct, flags); - - if (!pb_close_string_substream(stream, &substream)) - return false; - } - -#ifdef PB_ENABLE_MALLOC - if (!status) - pb_release(fields, dest_struct); -#endif - - return status; -} - -bool checkreturn pb_decode(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct) -{ - bool status; - - status = pb_decode_inner(stream, fields, dest_struct, 0); - -#ifdef PB_ENABLE_MALLOC - if (!status) - pb_release(fields, dest_struct); -#endif - - return status; -} - -#ifdef PB_ENABLE_MALLOC -/* Given an oneof field, if there has already been a field inside this oneof, - * release it before overwriting with a different one. */ -static bool pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *field) -{ - pb_field_iter_t old_field = *field; - pb_size_t old_tag = *(pb_size_t*)field->pSize; /* Previous which_ value */ - pb_size_t new_tag = field->tag; /* New which_ value */ - - if (old_tag == 0) - return true; /* Ok, no old data in union */ - - if (old_tag == new_tag) - return true; /* Ok, old data is of same type => merge */ - - /* Release old data. The find can fail if the message struct contains - * invalid data. */ - if (!pb_field_iter_find(&old_field, old_tag)) - PB_RETURN_ERROR(stream, "invalid union tag"); - - pb_release_single_field(&old_field); - - if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) - { - /* Initialize the pointer to NULL to make sure it is valid - * even in case of error return. */ - *(void**)field->pField = NULL; - field->pData = NULL; - } - - return true; -} - -static void pb_release_single_field(pb_field_iter_t *field) -{ - pb_type_t type; - type = field->type; - - if (PB_HTYPE(type) == PB_HTYPE_ONEOF) - { - if (*(pb_size_t*)field->pSize != field->tag) - return; /* This is not the current field in the union */ - } - - /* Release anything contained inside an extension or submsg. - * This has to be done even if the submsg itself is statically - * allocated. */ - if (PB_LTYPE(type) == PB_LTYPE_EXTENSION) - { - /* Release fields from all extensions in the linked list */ - pb_extension_t *ext = *(pb_extension_t**)field->pData; - while (ext != NULL) - { - pb_field_iter_t ext_iter; - if (pb_field_iter_begin_extension(&ext_iter, ext)) - { - pb_release_single_field(&ext_iter); - } - ext = ext->next; - } - } - else if (PB_LTYPE_IS_SUBMSG(type) && PB_ATYPE(type) != PB_ATYPE_CALLBACK) - { - /* Release fields in submessage or submsg array */ - pb_size_t count = 1; - - if (PB_ATYPE(type) == PB_ATYPE_POINTER) - { - field->pData = *(void**)field->pField; - } - else - { - field->pData = field->pField; - } - - if (PB_HTYPE(type) == PB_HTYPE_REPEATED) - { - count = *(pb_size_t*)field->pSize; - - if (PB_ATYPE(type) == PB_ATYPE_STATIC && count > field->array_size) - { - /* Protect against corrupted _count fields */ - count = field->array_size; - } - } - - if (field->pData) - { - for (; count > 0; count--) - { - pb_release(field->submsg_desc, field->pData); - field->pData = (char*)field->pData + field->data_size; - } - } - } - - if (PB_ATYPE(type) == PB_ATYPE_POINTER) - { - if (PB_HTYPE(type) == PB_HTYPE_REPEATED && - (PB_LTYPE(type) == PB_LTYPE_STRING || - PB_LTYPE(type) == PB_LTYPE_BYTES)) - { - /* Release entries in repeated string or bytes array */ - void **pItem = *(void***)field->pField; - pb_size_t count = *(pb_size_t*)field->pSize; - for (; count > 0; count--) - { - pb_free(*pItem); - *pItem++ = NULL; - } - } - - if (PB_HTYPE(type) == PB_HTYPE_REPEATED) - { - /* We are going to release the array, so set the size to 0 */ - *(pb_size_t*)field->pSize = 0; - } - - /* Release main pointer */ - pb_free(*(void**)field->pField); - *(void**)field->pField = NULL; - } -} - -void pb_release(const pb_msgdesc_t *fields, void *dest_struct) -{ - pb_field_iter_t iter; - - if (!dest_struct) - return; /* Ignore NULL pointers, similar to free() */ - - if (!pb_field_iter_begin(&iter, fields, dest_struct)) - return; /* Empty message type */ - - do - { - pb_release_single_field(&iter); - } while (pb_field_iter_next(&iter)); -} -#else -void pb_release(const pb_msgdesc_t *fields, void *dest_struct) -{ - /* Nothing to release without PB_ENABLE_MALLOC. */ - PB_UNUSED(fields); - PB_UNUSED(dest_struct); -} -#endif - -/* Field decoders */ - -bool pb_decode_bool(pb_istream_t *stream, bool *dest) -{ - uint32_t value; - if (!pb_decode_varint32(stream, &value)) - return false; - - *(bool*)dest = (value != 0); - return true; -} - -bool pb_decode_svarint(pb_istream_t *stream, pb_int64_t *dest) -{ - pb_uint64_t value; - if (!pb_decode_varint(stream, &value)) - return false; - - if (value & 1) - *dest = (pb_int64_t)(~(value >> 1)); - else - *dest = (pb_int64_t)(value >> 1); - - return true; -} - -bool pb_decode_fixed32(pb_istream_t *stream, void *dest) -{ - union { - uint32_t fixed32; - pb_byte_t bytes[4]; - } u; - - if (!pb_read(stream, u.bytes, 4)) - return false; - -#if defined(PB_LITTLE_ENDIAN_8BIT) && PB_LITTLE_ENDIAN_8BIT == 1 - /* fast path - if we know that we're on little endian, assign directly */ - *(uint32_t*)dest = u.fixed32; -#else - *(uint32_t*)dest = ((uint32_t)u.bytes[0] << 0) | - ((uint32_t)u.bytes[1] << 8) | - ((uint32_t)u.bytes[2] << 16) | - ((uint32_t)u.bytes[3] << 24); -#endif - return true; -} - -#ifndef PB_WITHOUT_64BIT -bool pb_decode_fixed64(pb_istream_t *stream, void *dest) -{ - union { - uint64_t fixed64; - pb_byte_t bytes[8]; - } u; - - if (!pb_read(stream, u.bytes, 8)) - return false; - -#if defined(PB_LITTLE_ENDIAN_8BIT) && PB_LITTLE_ENDIAN_8BIT == 1 - /* fast path - if we know that we're on little endian, assign directly */ - *(uint64_t*)dest = u.fixed64; -#else - *(uint64_t*)dest = ((uint64_t)u.bytes[0] << 0) | - ((uint64_t)u.bytes[1] << 8) | - ((uint64_t)u.bytes[2] << 16) | - ((uint64_t)u.bytes[3] << 24) | - ((uint64_t)u.bytes[4] << 32) | - ((uint64_t)u.bytes[5] << 40) | - ((uint64_t)u.bytes[6] << 48) | - ((uint64_t)u.bytes[7] << 56); -#endif - return true; -} -#endif - -static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_iter_t *field) -{ - return pb_decode_bool(stream, (bool*)field->pData); -} - -static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_iter_t *field) -{ - if (PB_LTYPE(field->type) == PB_LTYPE_UVARINT) - { - pb_uint64_t value, clamped; - if (!pb_decode_varint(stream, &value)) - return false; - - /* Cast to the proper field size, while checking for overflows */ - if (field->data_size == sizeof(pb_uint64_t)) - clamped = *(pb_uint64_t*)field->pData = value; - else if (field->data_size == sizeof(uint32_t)) - clamped = *(uint32_t*)field->pData = (uint32_t)value; - else if (field->data_size == sizeof(uint_least16_t)) - clamped = *(uint_least16_t*)field->pData = (uint_least16_t)value; - else if (field->data_size == sizeof(uint_least8_t)) - clamped = *(uint_least8_t*)field->pData = (uint_least8_t)value; - else - PB_RETURN_ERROR(stream, "invalid data_size"); - - if (clamped != value) - PB_RETURN_ERROR(stream, "integer too large"); - - return true; - } - else - { - pb_uint64_t value; - pb_int64_t svalue; - pb_int64_t clamped; - - if (PB_LTYPE(field->type) == PB_LTYPE_SVARINT) - { - if (!pb_decode_svarint(stream, &svalue)) - return false; - } - else - { - if (!pb_decode_varint(stream, &value)) - return false; - - /* See issue 97: Google's C++ protobuf allows negative varint values to - * be cast as int32_t, instead of the int64_t that should be used when - * encoding. Nanopb versions before 0.2.5 had a bug in encoding. In order to - * not break decoding of such messages, we cast <=32 bit fields to - * int32_t first to get the sign correct. - */ - if (field->data_size == sizeof(pb_int64_t)) - svalue = (pb_int64_t)value; - else - svalue = (int32_t)value; - } - - /* Cast to the proper field size, while checking for overflows */ - if (field->data_size == sizeof(pb_int64_t)) - clamped = *(pb_int64_t*)field->pData = svalue; - else if (field->data_size == sizeof(int32_t)) - clamped = *(int32_t*)field->pData = (int32_t)svalue; - else if (field->data_size == sizeof(int_least16_t)) - clamped = *(int_least16_t*)field->pData = (int_least16_t)svalue; - else if (field->data_size == sizeof(int_least8_t)) - clamped = *(int_least8_t*)field->pData = (int_least8_t)svalue; - else - PB_RETURN_ERROR(stream, "invalid data_size"); - - if (clamped != svalue) - PB_RETURN_ERROR(stream, "integer too large"); - - return true; - } -} - -static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_iter_t *field) -{ - uint32_t size; - size_t alloc_size; - pb_bytes_array_t *dest; - - if (!pb_decode_varint32(stream, &size)) - return false; - - if (size > PB_SIZE_MAX) - PB_RETURN_ERROR(stream, "bytes overflow"); - - alloc_size = PB_BYTES_ARRAY_T_ALLOCSIZE(size); - if (size > alloc_size) - PB_RETURN_ERROR(stream, "size too large"); - - if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) - { -#ifndef PB_ENABLE_MALLOC - PB_RETURN_ERROR(stream, "no malloc support"); -#else - if (stream->bytes_left < size) - PB_RETURN_ERROR(stream, "end-of-stream"); - - if (!allocate_field(stream, field->pData, alloc_size, 1)) - return false; - dest = *(pb_bytes_array_t**)field->pData; -#endif - } - else - { - if (alloc_size > field->data_size) - PB_RETURN_ERROR(stream, "bytes overflow"); - dest = (pb_bytes_array_t*)field->pData; - } - - dest->size = (pb_size_t)size; - return pb_read(stream, dest->bytes, (size_t)size); -} - -static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_iter_t *field) -{ - uint32_t size; - size_t alloc_size; - pb_byte_t *dest = (pb_byte_t*)field->pData; - - if (!pb_decode_varint32(stream, &size)) - return false; - - if (size == (uint32_t)-1) - PB_RETURN_ERROR(stream, "size too large"); - - /* Space for null terminator */ - alloc_size = (size_t)(size + 1); - - if (alloc_size < size) - PB_RETURN_ERROR(stream, "size too large"); - - if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) - { -#ifndef PB_ENABLE_MALLOC - PB_RETURN_ERROR(stream, "no malloc support"); -#else - if (stream->bytes_left < size) - PB_RETURN_ERROR(stream, "end-of-stream"); - - if (!allocate_field(stream, field->pData, alloc_size, 1)) - return false; - dest = *(pb_byte_t**)field->pData; -#endif - } - else - { - if (alloc_size > field->data_size) - PB_RETURN_ERROR(stream, "string overflow"); - } - - dest[size] = 0; - - if (!pb_read(stream, dest, (size_t)size)) - return false; - -#ifdef PB_VALIDATE_UTF8 - if (!pb_validate_utf8((const char*)dest)) - PB_RETURN_ERROR(stream, "invalid utf8"); -#endif - - return true; -} - -static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_iter_t *field) -{ - bool status = true; - bool submsg_consumed = false; - pb_istream_t substream; - - if (!pb_make_string_substream(stream, &substream)) - return false; - - if (field->submsg_desc == NULL) - PB_RETURN_ERROR(stream, "invalid field descriptor"); - - /* Submessages can have a separate message-level callback that is called - * before decoding the message. Typically it is used to set callback fields - * inside oneofs. */ - if (PB_LTYPE(field->type) == PB_LTYPE_SUBMSG_W_CB && field->pSize != NULL) - { - /* Message callback is stored right before pSize. */ - pb_callback_t *callback = (pb_callback_t*)field->pSize - 1; - if (callback->funcs.decode) - { - status = callback->funcs.decode(&substream, field, &callback->arg); - - if (substream.bytes_left == 0) - { - submsg_consumed = true; - } - } - } - - /* Now decode the submessage contents */ - if (status && !submsg_consumed) - { - unsigned int flags = 0; - - /* Static required/optional fields are already initialized by top-level - * pb_decode(), no need to initialize them again. */ - if (PB_ATYPE(field->type) == PB_ATYPE_STATIC && - PB_HTYPE(field->type) != PB_HTYPE_REPEATED) - { - flags = PB_DECODE_NOINIT; - } - - status = pb_decode_inner(&substream, field->submsg_desc, field->pData, flags); - } - - if (!pb_close_string_substream(stream, &substream)) - return false; - - return status; -} - -static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_iter_t *field) -{ - uint32_t size; - - if (!pb_decode_varint32(stream, &size)) - return false; - - if (size > PB_SIZE_MAX) - PB_RETURN_ERROR(stream, "bytes overflow"); - - if (size == 0) - { - /* As a special case, treat empty bytes string as all zeros for fixed_length_bytes. */ - memset(field->pData, 0, (size_t)field->data_size); - return true; - } - - if (size != field->data_size) - PB_RETURN_ERROR(stream, "incorrect fixed length bytes size"); - - return pb_read(stream, (pb_byte_t*)field->pData, (size_t)field->data_size); -} - -#ifdef PB_CONVERT_DOUBLE_FLOAT -bool pb_decode_double_as_float(pb_istream_t *stream, float *dest) -{ - uint_least8_t sign; - int exponent; - uint32_t mantissa; - uint64_t value; - union { float f; uint32_t i; } out; - - if (!pb_decode_fixed64(stream, &value)) - return false; - - /* Decompose input value */ - sign = (uint_least8_t)((value >> 63) & 1); - exponent = (int)((value >> 52) & 0x7FF) - 1023; - mantissa = (value >> 28) & 0xFFFFFF; /* Highest 24 bits */ - - /* Figure if value is in range representable by floats. */ - if (exponent == 1024) - { - /* Special value */ - exponent = 128; - mantissa >>= 1; - } - else - { - if (exponent > 127) - { - /* Too large, convert to infinity */ - exponent = 128; - mantissa = 0; - } - else if (exponent < -150) - { - /* Too small, convert to zero */ - exponent = -127; - mantissa = 0; - } - else if (exponent < -126) - { - /* Denormalized */ - mantissa |= 0x1000000; - mantissa >>= (-126 - exponent); - exponent = -127; - } - - /* Round off mantissa */ - mantissa = (mantissa + 1) >> 1; - - /* Check if mantissa went over 2.0 */ - if (mantissa & 0x800000) - { - exponent += 1; - mantissa &= 0x7FFFFF; - mantissa >>= 1; - } - } - - /* Combine fields */ - out.i = mantissa; - out.i |= (uint32_t)(exponent + 127) << 23; - out.i |= (uint32_t)sign << 31; - - *dest = out.f; - return true; -} -#endif diff --git a/src/network/pb_decode.h b/src/network/pb_decode.h deleted file mode 100644 index ae1d3ccf2eb..00000000000 --- a/src/network/pb_decode.h +++ /dev/null @@ -1,193 +0,0 @@ -/* pb_decode.h: Functions to decode protocol buffers. Depends on pb_decode.c. - * The main function is pb_decode. You also need an input stream, and the - * field descriptions created by nanopb_generator.py. - */ - -#ifndef PB_DECODE_H_INCLUDED -#define PB_DECODE_H_INCLUDED - -#include "pb.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Structure for defining custom input streams. You will need to provide - * a callback function to read the bytes from your storage, which can be - * for example a file or a network socket. - * - * The callback must conform to these rules: - * - * 1) Return false on IO errors. This will cause decoding to abort. - * 2) You can use state to store your own data (e.g. buffer pointer), - * and rely on pb_read to verify that no-body reads past bytes_left. - * 3) Your callback may be used with substreams, in which case bytes_left - * is different than from the main stream. Don't use bytes_left to compute - * any pointers. - */ -struct pb_istream_s -{ -#ifdef PB_BUFFER_ONLY - /* Callback pointer is not used in buffer-only configuration. - * Having an int pointer here allows binary compatibility but - * gives an error if someone tries to assign callback function. - */ - int *callback; -#else - bool (*callback)(pb_istream_t *stream, pb_byte_t *buf, size_t count); -#endif - - void *state; /* Free field for use by callback implementation */ - size_t bytes_left; - -#ifndef PB_NO_ERRMSG - const char *errmsg; -#endif -}; - -#ifndef PB_NO_ERRMSG -#define PB_ISTREAM_EMPTY {0,0,0,0} -#else -#define PB_ISTREAM_EMPTY {0,0,0} -#endif - -/*************************** - * Main decoding functions * - ***************************/ - -/* Decode a single protocol buffers message from input stream into a C structure. - * Returns true on success, false on any failure. - * The actual struct pointed to by dest must match the description in fields. - * Callback fields of the destination structure must be initialized by caller. - * All other fields will be initialized by this function. - * - * Example usage: - * MyMessage msg = {}; - * uint8_t buffer[64]; - * pb_istream_t stream; - * - * // ... read some data into buffer ... - * - * stream = pb_istream_from_buffer(buffer, count); - * pb_decode(&stream, MyMessage_fields, &msg); - */ -bool pb_decode(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct); - -/* Extended version of pb_decode, with several options to control - * the decoding process: - * - * PB_DECODE_NOINIT: Do not initialize the fields to default values. - * This is slightly faster if you do not need the default - * values and instead initialize the structure to 0 using - * e.g. memset(). This can also be used for merging two - * messages, i.e. combine already existing data with new - * values. - * - * PB_DECODE_DELIMITED: Input message starts with the message size as varint. - * Corresponds to parseDelimitedFrom() in Google's - * protobuf API. - * - * PB_DECODE_NULLTERMINATED: Stop reading when field tag is read as 0. This allows - * reading null terminated messages. - * NOTE: Until nanopb-0.4.0, pb_decode() also allows - * null-termination. This behaviour is not supported in - * most other protobuf implementations, so PB_DECODE_DELIMITED - * is a better option for compatibility. - * - * Multiple flags can be combined with bitwise or (| operator) - */ -#define PB_DECODE_NOINIT 0x01U -#define PB_DECODE_DELIMITED 0x02U -#define PB_DECODE_NULLTERMINATED 0x04U -bool pb_decode_ex(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct, unsigned int flags); - -/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ -#define pb_decode_noinit(s,f,d) pb_decode_ex(s,f,d, PB_DECODE_NOINIT) -#define pb_decode_delimited(s,f,d) pb_decode_ex(s,f,d, PB_DECODE_DELIMITED) -#define pb_decode_delimited_noinit(s,f,d) pb_decode_ex(s,f,d, PB_DECODE_DELIMITED | PB_DECODE_NOINIT) -#define pb_decode_nullterminated(s,f,d) pb_decode_ex(s,f,d, PB_DECODE_NULLTERMINATED) - -/* Release any allocated pointer fields. If you use dynamic allocation, you should - * call this for any successfully decoded message when you are done with it. If - * pb_decode() returns with an error, the message is already released. - */ -void pb_release(const pb_msgdesc_t *fields, void *dest_struct); - -/************************************** - * Functions for manipulating streams * - **************************************/ - -/* Create an input stream for reading from a memory buffer. - * - * msglen should be the actual length of the message, not the full size of - * allocated buffer. - * - * Alternatively, you can use a custom stream that reads directly from e.g. - * a file or a network socket. - */ -pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t msglen); - -/* Function to read from a pb_istream_t. You can use this if you need to - * read some custom header data, or to read data in field callbacks. - */ -bool pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count); - - -/************************************************ - * Helper functions for writing field callbacks * - ************************************************/ - -/* Decode the tag for the next field in the stream. Gives the wire type and - * field tag. At end of the message, returns false and sets eof to true. */ -bool pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof); - -/* Skip the field payload data, given the wire type. */ -bool pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type); - -/* Decode an integer in the varint format. This works for enum, int32, - * int64, uint32 and uint64 field types. */ -#ifndef PB_WITHOUT_64BIT -bool pb_decode_varint(pb_istream_t *stream, uint64_t *dest); -#else -#define pb_decode_varint pb_decode_varint32 -#endif - -/* Decode an integer in the varint format. This works for enum, int32, - * and uint32 field types. */ -bool pb_decode_varint32(pb_istream_t *stream, uint32_t *dest); - -/* Decode a bool value in varint format. */ -bool pb_decode_bool(pb_istream_t *stream, bool *dest); - -/* Decode an integer in the zig-zagged svarint format. This works for sint32 - * and sint64. */ -#ifndef PB_WITHOUT_64BIT -bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest); -#else -bool pb_decode_svarint(pb_istream_t *stream, int32_t *dest); -#endif - -/* Decode a fixed32, sfixed32 or float value. You need to pass a pointer to - * a 4-byte wide C variable. */ -bool pb_decode_fixed32(pb_istream_t *stream, void *dest); - -#ifndef PB_WITHOUT_64BIT -/* Decode a fixed64, sfixed64 or double value. You need to pass a pointer to - * a 8-byte wide C variable. */ -bool pb_decode_fixed64(pb_istream_t *stream, void *dest); -#endif - -#ifdef PB_CONVERT_DOUBLE_FLOAT -/* Decode a double value into float variable. */ -bool pb_decode_double_as_float(pb_istream_t *stream, float *dest); -#endif - -/* Make a limited-length substream for reading a PB_WT_STRING field. */ -bool pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream); -bool pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif diff --git a/src/network/pb_encode.c b/src/network/pb_encode.c deleted file mode 100644 index a4e30b47102..00000000000 --- a/src/network/pb_encode.c +++ /dev/null @@ -1,1001 +0,0 @@ -/* pb_encode.c -- encode a protobuf using minimal resources - * - * 2011 Petteri Aimonen - */ - -#include "pb.h" -#include "pb_encode.h" -#include "pb_common.h" - -/* Use the GCC warn_unused_result attribute to check that all return values - * are propagated correctly. On other compilers and gcc before 3.4.0 just - * ignore the annotation. - */ -#if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) - #define checkreturn -#else - #define checkreturn __attribute__((warn_unused_result)) -#endif - -/************************************** - * Declarations internal to this file * - **************************************/ -static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count); -static bool checkreturn encode_array(pb_ostream_t *stream, pb_field_iter_t *field); -static bool checkreturn pb_check_proto3_default_value(const pb_field_iter_t *field); -static bool checkreturn encode_basic_field(pb_ostream_t *stream, const pb_field_iter_t *field); -static bool checkreturn encode_callback_field(pb_ostream_t *stream, const pb_field_iter_t *field); -static bool checkreturn encode_field(pb_ostream_t *stream, pb_field_iter_t *field); -static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_iter_t *field); -static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension); -static bool checkreturn pb_encode_varint_32(pb_ostream_t *stream, uint32_t low, uint32_t high); -static bool checkreturn pb_enc_bool(pb_ostream_t *stream, const pb_field_iter_t *field); -static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_iter_t *field); -static bool checkreturn pb_enc_fixed(pb_ostream_t *stream, const pb_field_iter_t *field); -static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_iter_t *field); -static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_iter_t *field); -static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_iter_t *field); -static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_iter_t *field); - -#ifdef PB_WITHOUT_64BIT -#define pb_int64_t int32_t -#define pb_uint64_t uint32_t -#else -#define pb_int64_t int64_t -#define pb_uint64_t uint64_t -#endif - -/******************************* - * pb_ostream_t implementation * - *******************************/ - -static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count) -{ - pb_byte_t *dest = (pb_byte_t*)stream->state; - stream->state = dest + count; - - if ((dest != NULL) && (buf != NULL)) - memcpy(dest, buf, count * sizeof(pb_byte_t)); - - return true; -} - -pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize) -{ - pb_ostream_t stream; -#ifdef PB_BUFFER_ONLY - /* In PB_BUFFER_ONLY configuration the callback pointer is just int*. - * NULL pointer marks a sizing field, so put a non-NULL value to mark a buffer stream. - */ - static const int marker = 0; - stream.callback = ▮ -#else - stream.callback = &buf_write; -#endif - stream.state = buf; - stream.max_size = bufsize; - stream.bytes_written = 0; -#ifndef PB_NO_ERRMSG - stream.errmsg = NULL; -#endif - return stream; -} - -bool checkreturn pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count) -{ - if (count > 0 && stream->callback != NULL) - { - if (stream->bytes_written + count < stream->bytes_written || - stream->bytes_written + count > stream->max_size) - { - PB_RETURN_ERROR(stream, "stream full"); - } - -#ifdef PB_BUFFER_ONLY - if (!buf_write(stream, buf, count)) - PB_RETURN_ERROR(stream, "io error"); -#else - if (!stream->callback(stream, buf, count)) - PB_RETURN_ERROR(stream, "io error"); -#endif - } - - stream->bytes_written += count; - return true; -} - -/************************* - * Encode a single field * - *************************/ - -/* Read a bool value without causing undefined behavior even if the value - * is invalid. See issue #434 and - * https://stackoverflow.com/questions/27661768/weird-results-for-conditional - */ -static bool safe_read_bool(const void *pSize) -{ - const char *p = (const char *)pSize; - size_t i; - for (i = 0; i < sizeof(bool); i++) - { - if (p[i] != 0) - return true; - } - return false; -} - -/* Encode a static array. Handles the size calculations and possible packing. */ -static bool checkreturn encode_array(pb_ostream_t *stream, pb_field_iter_t *field) -{ - pb_size_t i; - pb_size_t count; -#ifndef PB_ENCODE_ARRAYS_UNPACKED - size_t size; -#endif - - count = *(pb_size_t*)field->pSize; - - if (count == 0) - return true; - - if (PB_ATYPE(field->type) != PB_ATYPE_POINTER && count > field->array_size) - PB_RETURN_ERROR(stream, "array max size exceeded"); - -#ifndef PB_ENCODE_ARRAYS_UNPACKED - /* We always pack arrays if the datatype allows it. */ - if (PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE) - { - if (!pb_encode_tag(stream, PB_WT_STRING, field->tag)) - return false; - - /* Determine the total size of packed array. */ - if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32) - { - size = 4 * (size_t)count; - } - else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64) - { - size = 8 * (size_t)count; - } - else - { - pb_ostream_t sizestream = PB_OSTREAM_SIZING; - void *pData_orig = field->pData; - for (i = 0; i < count; i++) - { - if (!pb_enc_varint(&sizestream, field)) - PB_RETURN_ERROR(stream, PB_GET_ERROR(&sizestream)); - field->pData = (char*)field->pData + field->data_size; - } - field->pData = pData_orig; - size = sizestream.bytes_written; - } - - if (!pb_encode_varint(stream, (pb_uint64_t)size)) - return false; - - if (stream->callback == NULL) - return pb_write(stream, NULL, size); /* Just sizing.. */ - - /* Write the data */ - for (i = 0; i < count; i++) - { - if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32 || PB_LTYPE(field->type) == PB_LTYPE_FIXED64) - { - if (!pb_enc_fixed(stream, field)) - return false; - } - else - { - if (!pb_enc_varint(stream, field)) - return false; - } - - field->pData = (char*)field->pData + field->data_size; - } - } - else /* Unpacked fields */ -#endif - { - for (i = 0; i < count; i++) - { - /* Normally the data is stored directly in the array entries, but - * for pointer-type string and bytes fields, the array entries are - * actually pointers themselves also. So we have to dereference once - * more to get to the actual data. */ - if (PB_ATYPE(field->type) == PB_ATYPE_POINTER && - (PB_LTYPE(field->type) == PB_LTYPE_STRING || - PB_LTYPE(field->type) == PB_LTYPE_BYTES)) - { - bool status; - void *pData_orig = field->pData; - field->pData = *(void* const*)field->pData; - - if (!field->pData) - { - /* Null pointer in array is treated as empty string / bytes */ - status = pb_encode_tag_for_field(stream, field) && - pb_encode_varint(stream, 0); - } - else - { - status = encode_basic_field(stream, field); - } - - field->pData = pData_orig; - - if (!status) - return false; - } - else - { - if (!encode_basic_field(stream, field)) - return false; - } - field->pData = (char*)field->pData + field->data_size; - } - } - - return true; -} - -/* In proto3, all fields are optional and are only encoded if their value is "non-zero". - * This function implements the check for the zero value. */ -static bool checkreturn pb_check_proto3_default_value(const pb_field_iter_t *field) -{ - pb_type_t type = field->type; - - if (PB_ATYPE(type) == PB_ATYPE_STATIC) - { - if (PB_HTYPE(type) == PB_HTYPE_REQUIRED) - { - /* Required proto2 fields inside proto3 submessage, pretty rare case */ - return false; - } - else if (PB_HTYPE(type) == PB_HTYPE_REPEATED) - { - /* Repeated fields inside proto3 submessage: present if count != 0 */ - return *(const pb_size_t*)field->pSize == 0; - } - else if (PB_HTYPE(type) == PB_HTYPE_ONEOF) - { - /* Oneof fields */ - return *(const pb_size_t*)field->pSize == 0; - } - else if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && field->pSize != NULL) - { - /* Proto2 optional fields inside proto3 message, or proto3 - * submessage fields. */ - return safe_read_bool(field->pSize) == false; - } - else if (field->descriptor->default_value) - { - /* Proto3 messages do not have default values, but proto2 messages - * can contain optional fields without has_fields (generator option 'proto3'). - * In this case they must always be encoded, to make sure that the - * non-zero default value is overwritten. - */ - return false; - } - - /* Rest is proto3 singular fields */ - if (PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) - { - /* Simple integer / float fields */ - pb_size_t i; - const char *p = (const char*)field->pData; - for (i = 0; i < field->data_size; i++) - { - if (p[i] != 0) - { - return false; - } - } - - return true; - } - else if (PB_LTYPE(type) == PB_LTYPE_BYTES) - { - const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)field->pData; - return bytes->size == 0; - } - else if (PB_LTYPE(type) == PB_LTYPE_STRING) - { - return *(const char*)field->pData == '\0'; - } - else if (PB_LTYPE(type) == PB_LTYPE_FIXED_LENGTH_BYTES) - { - /* Fixed length bytes is only empty if its length is fixed - * as 0. Which would be pretty strange, but we can check - * it anyway. */ - return field->data_size == 0; - } - else if (PB_LTYPE_IS_SUBMSG(type)) - { - /* Check all fields in the submessage to find if any of them - * are non-zero. The comparison cannot be done byte-per-byte - * because the C struct may contain padding bytes that must - * be skipped. Note that usually proto3 submessages have - * a separate has_field that is checked earlier in this if. - */ - pb_field_iter_t iter; - if (pb_field_iter_begin(&iter, field->submsg_desc, field->pData)) - { - do - { - if (!pb_check_proto3_default_value(&iter)) - { - return false; - } - } while (pb_field_iter_next(&iter)); - } - return true; - } - } - else if (PB_ATYPE(type) == PB_ATYPE_POINTER) - { - return field->pData == NULL; - } - else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK) - { - if (PB_LTYPE(type) == PB_LTYPE_EXTENSION) - { - const pb_extension_t *extension = *(const pb_extension_t* const *)field->pData; - return extension == NULL; - } - else if (field->descriptor->field_callback == pb_default_field_callback) - { - pb_callback_t *pCallback = (pb_callback_t*)field->pData; - return pCallback->funcs.encode == NULL; - } - else - { - return field->descriptor->field_callback == NULL; - } - } - - return false; /* Not typically reached, safe default for weird special cases. */ -} - -/* Encode a field with static or pointer allocation, i.e. one whose data - * is available to the encoder directly. */ -static bool checkreturn encode_basic_field(pb_ostream_t *stream, const pb_field_iter_t *field) -{ - if (!field->pData) - { - /* Missing pointer field */ - return true; - } - - if (!pb_encode_tag_for_field(stream, field)) - return false; - - switch (PB_LTYPE(field->type)) - { - case PB_LTYPE_BOOL: - return pb_enc_bool(stream, field); - - case PB_LTYPE_VARINT: - case PB_LTYPE_UVARINT: - case PB_LTYPE_SVARINT: - return pb_enc_varint(stream, field); - - case PB_LTYPE_FIXED32: - case PB_LTYPE_FIXED64: - return pb_enc_fixed(stream, field); - - case PB_LTYPE_BYTES: - return pb_enc_bytes(stream, field); - - case PB_LTYPE_STRING: - return pb_enc_string(stream, field); - - case PB_LTYPE_SUBMESSAGE: - case PB_LTYPE_SUBMSG_W_CB: - return pb_enc_submessage(stream, field); - - case PB_LTYPE_FIXED_LENGTH_BYTES: - return pb_enc_fixed_length_bytes(stream, field); - - default: - PB_RETURN_ERROR(stream, "invalid field type"); - } -} - -/* Encode a field with callback semantics. This means that a user function is - * called to provide and encode the actual data. */ -static bool checkreturn encode_callback_field(pb_ostream_t *stream, const pb_field_iter_t *field) -{ - if (field->descriptor->field_callback != NULL) - { - if (!field->descriptor->field_callback(NULL, stream, field)) - PB_RETURN_ERROR(stream, "callback error"); - } - return true; -} - -/* Encode a single field of any callback, pointer or static type. */ -static bool checkreturn encode_field(pb_ostream_t *stream, pb_field_iter_t *field) -{ - /* Check field presence */ - if (PB_HTYPE(field->type) == PB_HTYPE_ONEOF) - { - if (*(const pb_size_t*)field->pSize != field->tag) - { - /* Different type oneof field */ - return true; - } - } - else if (PB_HTYPE(field->type) == PB_HTYPE_OPTIONAL) - { - if (field->pSize) - { - if (safe_read_bool(field->pSize) == false) - { - /* Missing optional field */ - return true; - } - } - else if (PB_ATYPE(field->type) == PB_ATYPE_STATIC) - { - /* Proto3 singular field */ - if (pb_check_proto3_default_value(field)) - return true; - } - } - - if (!field->pData) - { - if (PB_HTYPE(field->type) == PB_HTYPE_REQUIRED) - PB_RETURN_ERROR(stream, "missing required field"); - - /* Pointer field set to NULL */ - return true; - } - - /* Then encode field contents */ - if (PB_ATYPE(field->type) == PB_ATYPE_CALLBACK) - { - return encode_callback_field(stream, field); - } - else if (PB_HTYPE(field->type) == PB_HTYPE_REPEATED) - { - return encode_array(stream, field); - } - else - { - return encode_basic_field(stream, field); - } -} - -/* Default handler for extension fields. Expects to have a pb_msgdesc_t - * pointer in the extension->type->arg field, pointing to a message with - * only one field in it. */ -static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension) -{ - pb_field_iter_t iter; - - if (!pb_field_iter_begin_extension_const(&iter, extension)) - PB_RETURN_ERROR(stream, "invalid extension"); - - return encode_field(stream, &iter); -} - - -/* Walk through all the registered extensions and give them a chance - * to encode themselves. */ -static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_iter_t *field) -{ - const pb_extension_t *extension = *(const pb_extension_t* const *)field->pData; - - while (extension) - { - bool status; - if (extension->type->encode) - status = extension->type->encode(stream, extension); - else - status = default_extension_encoder(stream, extension); - - if (!status) - return false; - - extension = extension->next; - } - - return true; -} - -/********************* - * Encode all fields * - *********************/ - -bool checkreturn pb_encode(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct) -{ - pb_field_iter_t iter; - if (!pb_field_iter_begin_const(&iter, fields, src_struct)) - return true; /* Empty message type */ - - do { - if (PB_LTYPE(iter.type) == PB_LTYPE_EXTENSION) - { - /* Special case for the extension field placeholder */ - if (!encode_extension_field(stream, &iter)) - return false; - } - else - { - /* Regular field */ - if (!encode_field(stream, &iter)) - return false; - } - } while (pb_field_iter_next(&iter)); - - return true; -} - -bool checkreturn pb_encode_ex(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct, unsigned int flags) -{ - if ((flags & PB_ENCODE_DELIMITED) != 0) - { - return pb_encode_submessage(stream, fields, src_struct); - } - else if ((flags & PB_ENCODE_NULLTERMINATED) != 0) - { - const pb_byte_t zero = 0; - - if (!pb_encode(stream, fields, src_struct)) - return false; - - return pb_write(stream, &zero, 1); - } - else - { - return pb_encode(stream, fields, src_struct); - } -} - -bool pb_get_encoded_size(size_t *size, const pb_msgdesc_t *fields, const void *src_struct) -{ - pb_ostream_t stream = PB_OSTREAM_SIZING; - - if (!pb_encode(&stream, fields, src_struct)) - return false; - - *size = stream.bytes_written; - return true; -} - -/******************** - * Helper functions * - ********************/ - -/* This function avoids 64-bit shifts as they are quite slow on many platforms. */ -static bool checkreturn pb_encode_varint_32(pb_ostream_t *stream, uint32_t low, uint32_t high) -{ - size_t i = 0; - pb_byte_t buffer[10]; - pb_byte_t byte = (pb_byte_t)(low & 0x7F); - low >>= 7; - - while (i < 4 && (low != 0 || high != 0)) - { - byte |= 0x80; - buffer[i++] = byte; - byte = (pb_byte_t)(low & 0x7F); - low >>= 7; - } - - if (high) - { - byte = (pb_byte_t)(byte | ((high & 0x07) << 4)); - high >>= 3; - - while (high) - { - byte |= 0x80; - buffer[i++] = byte; - byte = (pb_byte_t)(high & 0x7F); - high >>= 7; - } - } - - buffer[i++] = byte; - - return pb_write(stream, buffer, i); -} - -bool checkreturn pb_encode_varint(pb_ostream_t *stream, pb_uint64_t value) -{ - if (value <= 0x7F) - { - /* Fast path: single byte */ - pb_byte_t byte = (pb_byte_t)value; - return pb_write(stream, &byte, 1); - } - else - { -#ifdef PB_WITHOUT_64BIT - return pb_encode_varint_32(stream, value, 0); -#else - return pb_encode_varint_32(stream, (uint32_t)value, (uint32_t)(value >> 32)); -#endif - } -} - -bool checkreturn pb_encode_svarint(pb_ostream_t *stream, pb_int64_t value) -{ - pb_uint64_t zigzagged; - pb_uint64_t mask = ((pb_uint64_t)-1) >> 1; /* Satisfy clang -fsanitize=integer */ - if (value < 0) - zigzagged = ~(((pb_uint64_t)value & mask) << 1); - else - zigzagged = (pb_uint64_t)value << 1; - - return pb_encode_varint(stream, zigzagged); -} - -bool checkreturn pb_encode_fixed32(pb_ostream_t *stream, const void *value) -{ -#if defined(PB_LITTLE_ENDIAN_8BIT) && PB_LITTLE_ENDIAN_8BIT == 1 - /* Fast path if we know that we're on little endian */ - return pb_write(stream, (const pb_byte_t*)value, 4); -#else - uint32_t val = *(const uint32_t*)value; - pb_byte_t bytes[4]; - bytes[0] = (pb_byte_t)(val & 0xFF); - bytes[1] = (pb_byte_t)((val >> 8) & 0xFF); - bytes[2] = (pb_byte_t)((val >> 16) & 0xFF); - bytes[3] = (pb_byte_t)((val >> 24) & 0xFF); - return pb_write(stream, bytes, 4); -#endif -} - -#ifndef PB_WITHOUT_64BIT -bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value) -{ -#if defined(PB_LITTLE_ENDIAN_8BIT) && PB_LITTLE_ENDIAN_8BIT == 1 - /* Fast path if we know that we're on little endian */ - return pb_write(stream, (const pb_byte_t*)value, 8); -#else - uint64_t val = *(const uint64_t*)value; - pb_byte_t bytes[8]; - bytes[0] = (pb_byte_t)(val & 0xFF); - bytes[1] = (pb_byte_t)((val >> 8) & 0xFF); - bytes[2] = (pb_byte_t)((val >> 16) & 0xFF); - bytes[3] = (pb_byte_t)((val >> 24) & 0xFF); - bytes[4] = (pb_byte_t)((val >> 32) & 0xFF); - bytes[5] = (pb_byte_t)((val >> 40) & 0xFF); - bytes[6] = (pb_byte_t)((val >> 48) & 0xFF); - bytes[7] = (pb_byte_t)((val >> 56) & 0xFF); - return pb_write(stream, bytes, 8); -#endif -} -#endif - -bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number) -{ - pb_uint64_t tag = ((pb_uint64_t)field_number << 3) | wiretype; - return pb_encode_varint(stream, tag); -} - -bool pb_encode_tag_for_field ( pb_ostream_t* stream, const pb_field_iter_t* field ) -{ - pb_wire_type_t wiretype; - switch (PB_LTYPE(field->type)) - { - case PB_LTYPE_BOOL: - case PB_LTYPE_VARINT: - case PB_LTYPE_UVARINT: - case PB_LTYPE_SVARINT: - wiretype = PB_WT_VARINT; - break; - - case PB_LTYPE_FIXED32: - wiretype = PB_WT_32BIT; - break; - - case PB_LTYPE_FIXED64: - wiretype = PB_WT_64BIT; - break; - - case PB_LTYPE_BYTES: - case PB_LTYPE_STRING: - case PB_LTYPE_SUBMESSAGE: - case PB_LTYPE_SUBMSG_W_CB: - case PB_LTYPE_FIXED_LENGTH_BYTES: - wiretype = PB_WT_STRING; - break; - - default: - PB_RETURN_ERROR(stream, "invalid field type"); - } - - return pb_encode_tag(stream, wiretype, field->tag); -} - -bool checkreturn pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size) -{ - if (!pb_encode_varint(stream, (pb_uint64_t)size)) - return false; - - return pb_write(stream, buffer, size); -} - -bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct) -{ - /* First calculate the message size using a non-writing substream. */ - pb_ostream_t substream = PB_OSTREAM_SIZING; - size_t size; - bool status; - - if (!pb_encode(&substream, fields, src_struct)) - { -#ifndef PB_NO_ERRMSG - stream->errmsg = substream.errmsg; -#endif - return false; - } - - size = substream.bytes_written; - - if (!pb_encode_varint(stream, (pb_uint64_t)size)) - return false; - - if (stream->callback == NULL) - return pb_write(stream, NULL, size); /* Just sizing */ - - if (stream->bytes_written + size > stream->max_size) - PB_RETURN_ERROR(stream, "stream full"); - - /* Use a substream to verify that a callback doesn't write more than - * what it did the first time. */ - substream.callback = stream->callback; - substream.state = stream->state; - substream.max_size = size; - substream.bytes_written = 0; -#ifndef PB_NO_ERRMSG - substream.errmsg = NULL; -#endif - - status = pb_encode(&substream, fields, src_struct); - - stream->bytes_written += substream.bytes_written; - stream->state = substream.state; -#ifndef PB_NO_ERRMSG - stream->errmsg = substream.errmsg; -#endif - - if (substream.bytes_written != size) - PB_RETURN_ERROR(stream, "submsg size changed"); - - return status; -} - -/* Field encoders */ - -static bool checkreturn pb_enc_bool(pb_ostream_t *stream, const pb_field_iter_t *field) -{ - uint32_t value = safe_read_bool(field->pData) ? 1 : 0; - PB_UNUSED(field); - return pb_encode_varint(stream, value); -} - -static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_iter_t *field) -{ - if (PB_LTYPE(field->type) == PB_LTYPE_UVARINT) - { - /* Perform unsigned integer extension */ - pb_uint64_t value = 0; - - if (field->data_size == sizeof(uint_least8_t)) - value = *(const uint_least8_t*)field->pData; - else if (field->data_size == sizeof(uint_least16_t)) - value = *(const uint_least16_t*)field->pData; - else if (field->data_size == sizeof(uint32_t)) - value = *(const uint32_t*)field->pData; - else if (field->data_size == sizeof(pb_uint64_t)) - value = *(const pb_uint64_t*)field->pData; - else - PB_RETURN_ERROR(stream, "invalid data_size"); - - return pb_encode_varint(stream, value); - } - else - { - /* Perform signed integer extension */ - pb_int64_t value = 0; - - if (field->data_size == sizeof(int_least8_t)) - value = *(const int_least8_t*)field->pData; - else if (field->data_size == sizeof(int_least16_t)) - value = *(const int_least16_t*)field->pData; - else if (field->data_size == sizeof(int32_t)) - value = *(const int32_t*)field->pData; - else if (field->data_size == sizeof(pb_int64_t)) - value = *(const pb_int64_t*)field->pData; - else - PB_RETURN_ERROR(stream, "invalid data_size"); - - if (PB_LTYPE(field->type) == PB_LTYPE_SVARINT) - return pb_encode_svarint(stream, value); -#ifdef PB_WITHOUT_64BIT - else if (value < 0) - return pb_encode_varint_32(stream, (uint32_t)value, (uint32_t)-1); -#endif - else - return pb_encode_varint(stream, (pb_uint64_t)value); - - } -} - -static bool checkreturn pb_enc_fixed(pb_ostream_t *stream, const pb_field_iter_t *field) -{ -#ifdef PB_CONVERT_DOUBLE_FLOAT - if (field->data_size == sizeof(float) && PB_LTYPE(field->type) == PB_LTYPE_FIXED64) - { - return pb_encode_float_as_double(stream, *(float*)field->pData); - } -#endif - - if (field->data_size == sizeof(uint32_t)) - { - return pb_encode_fixed32(stream, field->pData); - } -#ifndef PB_WITHOUT_64BIT - else if (field->data_size == sizeof(uint64_t)) - { - return pb_encode_fixed64(stream, field->pData); - } -#endif - else - { - PB_RETURN_ERROR(stream, "invalid data_size"); - } -} - -static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_iter_t *field) -{ - const pb_bytes_array_t *bytes = NULL; - - bytes = (const pb_bytes_array_t*)field->pData; - - if (bytes == NULL) - { - /* Treat null pointer as an empty bytes field */ - return pb_encode_string(stream, NULL, 0); - } - - if (PB_ATYPE(field->type) == PB_ATYPE_STATIC && - bytes->size > field->data_size - offsetof(pb_bytes_array_t, bytes)) - { - PB_RETURN_ERROR(stream, "bytes size exceeded"); - } - - return pb_encode_string(stream, bytes->bytes, (size_t)bytes->size); -} - -static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_iter_t *field) -{ - size_t size = 0; - size_t max_size = (size_t)field->data_size; - const char *str = (const char*)field->pData; - - if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) - { - max_size = (size_t)-1; - } - else - { - /* pb_dec_string() assumes string fields end with a null - * terminator when the type isn't PB_ATYPE_POINTER, so we - * shouldn't allow more than max-1 bytes to be written to - * allow space for the null terminator. - */ - if (max_size == 0) - PB_RETURN_ERROR(stream, "zero-length string"); - - max_size -= 1; - } - - - if (str == NULL) - { - size = 0; /* Treat null pointer as an empty string */ - } - else - { - const char *p = str; - - /* strnlen() is not always available, so just use a loop */ - while (size < max_size && *p != '\0') - { - size++; - p++; - } - - if (*p != '\0') - { - PB_RETURN_ERROR(stream, "unterminated string"); - } - } - -#ifdef PB_VALIDATE_UTF8 - if (!pb_validate_utf8(str)) - PB_RETURN_ERROR(stream, "invalid utf8"); -#endif - - return pb_encode_string(stream, (const pb_byte_t*)str, size); -} - -static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_iter_t *field) -{ - if (field->submsg_desc == NULL) - PB_RETURN_ERROR(stream, "invalid field descriptor"); - - if (PB_LTYPE(field->type) == PB_LTYPE_SUBMSG_W_CB && field->pSize != NULL) - { - /* Message callback is stored right before pSize. */ - pb_callback_t *callback = (pb_callback_t*)field->pSize - 1; - if (callback->funcs.encode) - { - if (!callback->funcs.encode(stream, field, &callback->arg)) - return false; - } - } - - return pb_encode_submessage(stream, field->submsg_desc, field->pData); -} - -static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_iter_t *field) -{ - return pb_encode_string(stream, (const pb_byte_t*)field->pData, (size_t)field->data_size); -} - -#ifdef PB_CONVERT_DOUBLE_FLOAT -bool pb_encode_float_as_double(pb_ostream_t *stream, float value) -{ - union { float f; uint32_t i; } in; - uint_least8_t sign; - int exponent; - uint64_t mantissa; - - in.f = value; - - /* Decompose input value */ - sign = (uint_least8_t)((in.i >> 31) & 1); - exponent = (int)((in.i >> 23) & 0xFF) - 127; - mantissa = in.i & 0x7FFFFF; - - if (exponent == 128) - { - /* Special value (NaN etc.) */ - exponent = 1024; - } - else if (exponent == -127) - { - if (!mantissa) - { - /* Zero */ - exponent = -1023; - } - else - { - /* Denormalized */ - mantissa <<= 1; - while (!(mantissa & 0x800000)) - { - mantissa <<= 1; - exponent--; - } - mantissa &= 0x7FFFFF; - } - } - - /* Combine fields */ - mantissa <<= 29; - mantissa |= (uint64_t)(exponent + 1023) << 52; - mantissa |= (uint64_t)sign << 63; - - return pb_encode_fixed64(stream, &mantissa); -} -#endif diff --git a/src/network/pb_encode.h b/src/network/pb_encode.h deleted file mode 100644 index 891368322f4..00000000000 --- a/src/network/pb_encode.h +++ /dev/null @@ -1,185 +0,0 @@ -/* pb_encode.h: Functions to encode protocol buffers. Depends on pb_encode.c. - * The main function is pb_encode. You also need an output stream, and the - * field descriptions created by nanopb_generator.py. - */ - -#ifndef PB_ENCODE_H_INCLUDED -#define PB_ENCODE_H_INCLUDED - -#include "pb.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Structure for defining custom output streams. You will need to provide - * a callback function to write the bytes to your storage, which can be - * for example a file or a network socket. - * - * The callback must conform to these rules: - * - * 1) Return false on IO errors. This will cause encoding to abort. - * 2) You can use state to store your own data (e.g. buffer pointer). - * 3) pb_write will update bytes_written after your callback runs. - * 4) Substreams will modify max_size and bytes_written. Don't use them - * to calculate any pointers. - */ -struct pb_ostream_s -{ -#ifdef PB_BUFFER_ONLY - /* Callback pointer is not used in buffer-only configuration. - * Having an int pointer here allows binary compatibility but - * gives an error if someone tries to assign callback function. - * Also, NULL pointer marks a 'sizing stream' that does not - * write anything. - */ - const int *callback; -#else - bool (*callback)(pb_ostream_t *stream, const pb_byte_t *buf, size_t count); -#endif - void *state; /* Free field for use by callback implementation. */ - size_t max_size; /* Limit number of output bytes written (or use SIZE_MAX). */ - size_t bytes_written; /* Number of bytes written so far. */ - -#ifndef PB_NO_ERRMSG - const char *errmsg; -#endif -}; - -/*************************** - * Main encoding functions * - ***************************/ - -/* Encode a single protocol buffers message from C structure into a stream. - * Returns true on success, false on any failure. - * The actual struct pointed to by src_struct must match the description in fields. - * All required fields in the struct are assumed to have been filled in. - * - * Example usage: - * MyMessage msg = {}; - * uint8_t buffer[64]; - * pb_ostream_t stream; - * - * msg.field1 = 42; - * stream = pb_ostream_from_buffer(buffer, sizeof(buffer)); - * pb_encode(&stream, MyMessage_fields, &msg); - */ -bool pb_encode(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct); - -/* Extended version of pb_encode, with several options to control the - * encoding process: - * - * PB_ENCODE_DELIMITED: Prepend the length of message as a varint. - * Corresponds to writeDelimitedTo() in Google's - * protobuf API. - * - * PB_ENCODE_NULLTERMINATED: Append a null byte to the message for termination. - * NOTE: This behaviour is not supported in most other - * protobuf implementations, so PB_ENCODE_DELIMITED - * is a better option for compatibility. - */ -#define PB_ENCODE_DELIMITED 0x02U -#define PB_ENCODE_NULLTERMINATED 0x04U -bool pb_encode_ex(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct, unsigned int flags); - -/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ -#define pb_encode_delimited(s,f,d) pb_encode_ex(s,f,d, PB_ENCODE_DELIMITED) -#define pb_encode_nullterminated(s,f,d) pb_encode_ex(s,f,d, PB_ENCODE_NULLTERMINATED) - -/* Encode the message to get the size of the encoded data, but do not store - * the data. */ -bool pb_get_encoded_size(size_t *size, const pb_msgdesc_t *fields, const void *src_struct); - -/************************************** - * Functions for manipulating streams * - **************************************/ - -/* Create an output stream for writing into a memory buffer. - * The number of bytes written can be found in stream.bytes_written after - * encoding the message. - * - * Alternatively, you can use a custom stream that writes directly to e.g. - * a file or a network socket. - */ -pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize); - -/* Pseudo-stream for measuring the size of a message without actually storing - * the encoded data. - * - * Example usage: - * MyMessage msg = {}; - * pb_ostream_t stream = PB_OSTREAM_SIZING; - * pb_encode(&stream, MyMessage_fields, &msg); - * printf("Message size is %d\n", stream.bytes_written); - */ -#ifndef PB_NO_ERRMSG -#define PB_OSTREAM_SIZING {0,0,0,0,0} -#else -#define PB_OSTREAM_SIZING {0,0,0,0} -#endif - -/* Function to write into a pb_ostream_t stream. You can use this if you need - * to append or prepend some custom headers to the message. - */ -bool pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count); - - -/************************************************ - * Helper functions for writing field callbacks * - ************************************************/ - -/* Encode field header based on type and field number defined in the field - * structure. Call this from the callback before writing out field contents. */ -bool pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_iter_t *field); - -/* Encode field header by manually specifying wire type. You need to use this - * if you want to write out packed arrays from a callback field. */ -bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number); - -/* Encode an integer in the varint format. - * This works for bool, enum, int32, int64, uint32 and uint64 field types. */ -#ifndef PB_WITHOUT_64BIT -bool pb_encode_varint(pb_ostream_t *stream, uint64_t value); -#else -bool pb_encode_varint(pb_ostream_t *stream, uint32_t value); -#endif - -/* Encode an integer in the zig-zagged svarint format. - * This works for sint32 and sint64. */ -#ifndef PB_WITHOUT_64BIT -bool pb_encode_svarint(pb_ostream_t *stream, int64_t value); -#else -bool pb_encode_svarint(pb_ostream_t *stream, int32_t value); -#endif - -/* Encode a string or bytes type field. For strings, pass strlen(s) as size. */ -bool pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size); - -/* Encode a fixed32, sfixed32 or float value. - * You need to pass a pointer to a 4-byte wide C variable. */ -bool pb_encode_fixed32(pb_ostream_t *stream, const void *value); - -#ifndef PB_WITHOUT_64BIT -/* Encode a fixed64, sfixed64 or double value. - * You need to pass a pointer to a 8-byte wide C variable. */ -bool pb_encode_fixed64(pb_ostream_t *stream, const void *value); -#endif - -#ifdef PB_CONVERT_DOUBLE_FLOAT -/* Encode a float value so that it appears like a double in the encoded - * message. */ -bool pb_encode_float_as_double(pb_ostream_t *stream, float value); -#endif - -/* Encode a submessage field. - * You need to pass the pb_field_t array and pointer to struct, just like - * with pb_encode(). This internally encodes the submessage twice, first to - * calculate message size and then to actually write it out. - */ -bool pb_encode_submessage(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif diff --git a/src/nvr_at.c b/src/nvr_at.c index ae7bd8bb490..07588fb01b7 100644 --- a/src/nvr_at.c +++ b/src/nvr_at.c @@ -635,6 +635,13 @@ nvr_reg_write(uint16_t reg, uint8_t val, void *priv) nvr_reg_common_write(reg, val, nvr, local); break; + case 0x39: + if (machines[machine].init == machine_at_bx6_init) + nvr_reg_common_write(reg, val | 0x08, nvr, local); + else + nvr_reg_common_write(reg, val, nvr, local); + break; + default: /* non-RTC registers are just NVRAM */ nvr_reg_common_write(reg, val, nvr, local); break; @@ -794,6 +801,14 @@ nvr_read(uint16_t addr, void *priv) ret = nvr->regs[local->addr[addr_id]]; break; + case 0x39: + if (!(local->lock[local->addr[addr_id]] & 0x02)) { + ret = nvr->regs[local->addr[addr_id]]; + if (machines[machine].init == machine_at_bx6_init) + ret |= 0x08; + } + break; + case 0x3e: case 0x3f: if (!nvr->is_new && (local->flags & FLAG_AMI_1995_HACK)) { @@ -1158,8 +1173,15 @@ nvr_at_init(const device_t *info) local->cent = RTC_CENTURY_VIA; break; case 8: /* Epson Equity LT */ - nvr->irq = -1; - local->cent = RTC_CENTURY_ELT; + if ((info->local & 0x1f) == 0x18) { + local->flags |= (FLAG_PIIX4 | FLAG_AMI_1995_HACK); + local->def = 0x00; + nvr->irq = 8; + local->cent = RTC_CENTURY_AT; + } else { + nvr->irq = -1; + local->cent = RTC_CENTURY_ELT; + } break; default: @@ -1169,6 +1191,9 @@ nvr_at_init(const device_t *info) if (info->local & 0x20) local->def = 0x00; + if (machines[machine].init == machine_at_monsoon_init) + local->def = 0xff; + if (info->local & 0x40) local->flags |= FLAG_MULTI_BANK; @@ -1204,7 +1229,8 @@ nvr_at_init(const device_t *info) io_sethandler(0x0070, 2, nvr_read, NULL, NULL, nvr_write, NULL, NULL, nvr); } - if (((info->local & 0x1f) == 0x11) || ((info->local & 0x1f) == 0x17)) { + if (((info->local & 0x1f) == 0x11) || ((info->local & 0x1f) == 0x17) || + ((info->local & 0x1f) == 0x18)) { io_sethandler(0x0072, 2, nvr_read, NULL, NULL, nvr_write, NULL, NULL, nvr); } @@ -1216,6 +1242,9 @@ nvr_at_init(const device_t *info) if (nvr->is_new && (machines[machine].init == machine_at_spitfire_init)) nvr->regs[0x33] = nvr->regs[0x34] = 0xff; + if (nvr->is_new && (machines[machine].init == machine_at_bx6_init)) + nvr->regs[0x39] = 0x09; + return nvr; } @@ -1427,6 +1456,20 @@ const device_t via_nvr_device = { .config = NULL }; +const device_t piix4_ami_1995_nvr_device = { + .name = "Intel PIIX4 AMI WinBIOS 1995 PC/AT NVRAM", + .internal_name = "piix4_ami_1995_nvr", + .flags = DEVICE_ISA16, + .local = 0x10 | 8, + .init = nvr_at_init, + .close = nvr_at_close, + .reset = nvr_at_reset, + .available = NULL, + .speed_changed = nvr_at_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + const device_t p6rp4_nvr_device = { .name = "ASUS P/I-P6RP4 PC/AT NVRAM", .internal_name = "p6rp4_nvr", diff --git a/src/printer/prt_ps.c b/src/printer/prt_ps.c index 3a32303949f..adf57a52376 100644 --- a/src/printer/prt_ps.c +++ b/src/printer/prt_ps.c @@ -77,8 +77,12 @@ typedef struct ps_t { bool error; bool autofeed; bool pcl; - bool pcl_escape; + bool pending; + bool pjl; + bool pjl_command; uint8_t ctrl; + uint8_t pcl_escape; + uint16_t pjl_command_start; char printer_path[260]; @@ -116,21 +120,6 @@ static dllimp_t ghostscript_imports[] = { static void *ghostscript_handle = NULL; -static void -reset_ps(ps_t *dev) -{ - if (dev == NULL) - return; - - dev->ack = false; - - dev->buffer[0] = 0; - dev->buffer_pos = 0; - - timer_disable(&dev->pulse_timer); - timer_stop(&dev->timeout_timer); -} - static void pulse_timer(void *priv) { @@ -198,13 +187,37 @@ convert_to_pdf(ps_t *dev) return code; } +static void +reset_ps(ps_t *dev) +{ + if (dev == NULL) + return; + + dev->ack = false; + + if (dev->pending) { + if (ghostscript_handle != NULL) + convert_to_pdf(dev); + + dev->filename[0] = 0; + + dev->pending = false; + } + + dev->buffer[0] = 0; + dev->buffer_pos = 0; + + timer_disable(&dev->pulse_timer); + timer_stop(&dev->timeout_timer); +} + static void write_buffer(ps_t *dev, bool finish) { char path[1024]; FILE *fp; - if (dev->buffer[0] == 0) + if (dev->buffer_pos == 0) return; if (dev->filename[0] == 0) @@ -235,7 +248,10 @@ write_buffer(ps_t *dev, bool finish) convert_to_pdf(dev); dev->filename[0] = 0; - } + + dev->pending = false; + } else + dev->pending = true; } static void @@ -243,7 +259,16 @@ timeout_timer(void *priv) { ps_t *dev = (ps_t *) priv; - write_buffer(dev, true); + if (dev->buffer_pos != 0) + write_buffer(dev, true); + else if (dev->pending) { + if (ghostscript_handle != NULL) + convert_to_pdf(dev); + + dev->filename[0] = 0; + + dev->pending = false; + } timer_stop(&dev->timeout_timer); } @@ -264,23 +289,65 @@ process_data(ps_t *dev) { /* On PCL, check for escape sequences. */ if (dev->pcl) { - if (dev->data == 0x1B) - dev->pcl_escape = true; - else if (dev->pcl_escape) { - dev->pcl_escape = false; - if (dev->data == 0xE) { - dev->buffer[dev->buffer_pos++] = dev->data; - dev->buffer[dev->buffer_pos] = 0; - - if (dev->buffer_pos > 2) - write_buffer(dev, true); - - return; + if (dev->pjl) { + dev->buffer[dev->buffer_pos++] = dev->data; + + /* Filter out any PJL commands. */ + if (dev->pjl_command && (dev->data == '\n')) { + dev->pjl_command = false; + if (!memcmp(&(dev->buffer[dev->pjl_command_start]), "@PJL ENTER LANGUAGE=PCL", 0x17)) + dev->pjl = false; + else if (!memcmp(&(dev->buffer[dev->pjl_command_start]), "@PJL ENTER LANGUAGE=POSTSCRIPT", 0x1e)) + fatal("Printing PostScript using the PCL printer is not (yet) supported!\n"); + dev->buffer_pos = dev->pjl_command_start; + } else if (!dev->pjl_command && (dev->buffer_pos >= 0x05) && !memcmp(&(dev->buffer[dev->buffer_pos - 0x5]), "@PJL ", 0x05)) { + dev->pjl_command = true; + dev->pjl_command_start = dev->buffer_pos - 0x05; } + + dev->buffer[dev->buffer_pos] = 0; + return; + } else if (dev->data == 0x1b) + dev->pcl_escape = 1; + else switch (dev->pcl_escape) { + case 1: + dev->pcl_escape = (dev->data == 0x25) ? 2 : 0; + if (dev->data == 0x0e) { + dev->buffer[dev->buffer_pos++] = dev->data; + dev->buffer[dev->buffer_pos] = 0; + + if (dev->buffer_pos > 2) + write_buffer(dev, true); + + return; + } + break; + case 2: + dev->pcl_escape = (dev->data == 0x2d) ? 3 : 0; + break; + case 3: + dev->pcl_escape = (dev->data == 0x31) ? 4 : 0; + break; + case 4: + dev->pcl_escape = (dev->data == 0x32) ? 5 : 0; + break; + case 5: + dev->pcl_escape = (dev->data == 0x33) ? 6 : 0; + break; + case 6: + dev->pcl_escape = (dev->data == 0x34) ? 7 : 0; + break; + case 7: + dev->pcl_escape = (dev->data == 0x35) ? 8 : 0; + break; + case 8: + dev->pcl_escape = 0; + if (dev->data == 0x58) + dev->pjl = true; + break; } - } - /* On PostScript, check for non-printable characters. */ - else if ((dev->data < 0x20) || (dev->data == 0x7f)) { + } else if ((dev->data < 0x20) || (dev->data == 0x7f)) { + /* On PostScript, check for non-printable characters. */ switch (dev->data) { /* The following characters are considered white-space by the PostScript specification */ diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index 1c61f555985..b7d39109e50 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -275,10 +275,6 @@ if(EMU_BUILD_NUM) ) endif() -if(NETSWITCH) - target_compile_definitions(ui PRIVATE USE_NETSWITCH) -endif() - if(RTMIDI) target_compile_definitions(ui PRIVATE USE_RTMIDI) endif() diff --git a/src/qt/dummy_cdrom_ioctl.c b/src/qt/dummy_cdrom_ioctl.c index af8679ecc66..9b7a8bfbfb5 100644 --- a/src/qt/dummy_cdrom_ioctl.c +++ b/src/qt/dummy_cdrom_ioctl.c @@ -24,6 +24,7 @@ #include #include #define HAVE_STDARG_H +#include <86box/86box.h> #include <86box/scsi_device.h> #include <86box/cdrom.h> #include <86box/log.h> diff --git a/src/qt/icons/86Box-gray.ico b/src/qt/icons/86Box-gray.ico index c9cbad17d65..68f278334a1 100644 Binary files a/src/qt/icons/86Box-gray.ico and b/src/qt/icons/86Box-gray.ico differ diff --git a/src/qt/icons/86Box-green.ico b/src/qt/icons/86Box-green.ico index 5c783674d42..77b3419abbf 100644 Binary files a/src/qt/icons/86Box-green.ico and b/src/qt/icons/86Box-green.ico differ diff --git a/src/qt/icons/86Box-red.ico b/src/qt/icons/86Box-red.ico index 6b4666c4335..36fbd2c9964 100644 Binary files a/src/qt/icons/86Box-red.ico and b/src/qt/icons/86Box-red.ico differ diff --git a/src/qt/icons/86Box-yellow.ico b/src/qt/icons/86Box-yellow.ico index c3822c89b28..f6abcff4f07 100644 Binary files a/src/qt/icons/86Box-yellow.ico and b/src/qt/icons/86Box-yellow.ico differ diff --git a/src/qt/icons/acpi_shutdown.ico b/src/qt/icons/acpi_shutdown.ico index a2493b8031b..03a7503ec47 100644 Binary files a/src/qt/icons/acpi_shutdown.ico and b/src/qt/icons/acpi_shutdown.ico differ diff --git a/src/qt/icons/copy_raw_screenshot.ico b/src/qt/icons/copy_raw_screenshot.ico new file mode 100644 index 00000000000..a153305b7ba Binary files /dev/null and b/src/qt/icons/copy_raw_screenshot.ico differ diff --git a/src/qt/icons/copy_screenshot.ico b/src/qt/icons/copy_screenshot.ico new file mode 100644 index 00000000000..5ea6bc7057b Binary files /dev/null and b/src/qt/icons/copy_screenshot.ico differ diff --git a/src/qt/icons/hard_reset.ico b/src/qt/icons/hard_reset.ico index d0494f40bb8..46642e01b8c 100644 Binary files a/src/qt/icons/hard_reset.ico and b/src/qt/icons/hard_reset.ico differ diff --git a/src/qt/icons/interpreter.ico b/src/qt/icons/interpreter.ico new file mode 100644 index 00000000000..75add61f062 Binary files /dev/null and b/src/qt/icons/interpreter.ico differ diff --git a/src/qt/icons/new.ico b/src/qt/icons/new.ico index b3e0c16b068..9e04337d00d 100644 Binary files a/src/qt/icons/new.ico and b/src/qt/icons/new.ico differ diff --git a/src/qt/icons/new_vm.ico b/src/qt/icons/new_vm.ico new file mode 100644 index 00000000000..27e4a260609 Binary files /dev/null and b/src/qt/icons/new_vm.ico differ diff --git a/src/qt/icons/pause.ico b/src/qt/icons/pause.ico index a57bc0a0855..3f7079fd758 100644 Binary files a/src/qt/icons/pause.ico and b/src/qt/icons/pause.ico differ diff --git a/src/qt/icons/recompiler.ico b/src/qt/icons/recompiler.ico new file mode 100644 index 00000000000..c00853f2c31 Binary files /dev/null and b/src/qt/icons/recompiler.ico differ diff --git a/src/qt/icons/record.ico b/src/qt/icons/record.ico index 357563594e7..3715837b10a 100644 Binary files a/src/qt/icons/record.ico and b/src/qt/icons/record.ico differ diff --git a/src/qt/icons/run.ico b/src/qt/icons/run.ico index c088eb59dc4..89091467282 100644 Binary files a/src/qt/icons/run.ico and b/src/qt/icons/run.ico differ diff --git a/src/qt/icons/send_cad.ico b/src/qt/icons/send_cad.ico index e3e64a74349..e3f27c7830b 100644 Binary files a/src/qt/icons/send_cad.ico and b/src/qt/icons/send_cad.ico differ diff --git a/src/qt/icons/settings.ico b/src/qt/icons/settings.ico index ed64740b27f..21a7371afd2 100644 Binary files a/src/qt/icons/settings.ico and b/src/qt/icons/settings.ico differ diff --git a/src/qt/icons/take_raw_screenshot.ico b/src/qt/icons/take_raw_screenshot.ico new file mode 100644 index 00000000000..19a0a15e8c0 Binary files /dev/null and b/src/qt/icons/take_raw_screenshot.ico differ diff --git a/src/qt/icons/take_screenshot.ico b/src/qt/icons/take_screenshot.ico new file mode 100644 index 00000000000..66f83ebbdf5 Binary files /dev/null and b/src/qt/icons/take_screenshot.ico differ diff --git a/src/qt/languages/86box.pot b/src/qt/languages/86box.pot index 8bedf31f846..c5d1d25144d 100644 --- a/src/qt/languages/86box.pot +++ b/src/qt/languages/86box.pot @@ -66,7 +66,7 @@ msgstr "" msgid "&VNC" msgstr "" -msgid "Specify &dimensions..." +msgid "Specify &dimensions…" msgstr "" msgid "Force &4:3 display ratio" @@ -192,10 +192,10 @@ msgstr "" msgid "&Tools" msgstr "" -msgid "&Settings..." +msgid "&Settings…" msgstr "" -msgid "Settings..." +msgid "Settings…" msgstr "" msgid "&Update status bar icons" @@ -204,16 +204,37 @@ msgstr "" msgid "Take s&creenshot" msgstr "" +msgid "Take screenshot" +msgstr "" + +msgid "Take &raw screenshot" +msgstr "" + +msgid "Take raw screenshot" +msgstr "" + +msgid "C&opy screenshot" +msgstr "" + +msgid "Copy screenshot" +msgstr "" + +msgid "Copy r&aw screenshot" +msgstr "" + +msgid "Copy raw screenshot" +msgstr "" + msgid "S&ound" msgstr "" -msgid "&Preferences..." +msgid "&Preferences…" msgstr "" msgid "Enable &Discord integration" msgstr "" -msgid "Sound &gain..." +msgid "Sound &gain…" msgstr "" msgid "Begin trace" @@ -225,19 +246,19 @@ msgstr "" msgid "&Help" msgstr "" -msgid "&Documentation..." +msgid "&Documentation…" msgstr "" -msgid "&About 86Box..." +msgid "&About 86Box…" msgstr "" -msgid "&New image..." +msgid "&New image…" msgstr "" -msgid "&Existing image..." +msgid "&Existing image…" msgstr "" -msgid "Existing image (&Write-protected)..." +msgid "Existing image (&Write-protected)…" msgstr "" msgid "&Record" @@ -255,10 +276,10 @@ msgstr "" msgid "E&ject" msgstr "" -msgid "&Image..." +msgid "&Image…" msgstr "" -msgid "E&xport to 86F..." +msgid "E&xport to 86F…" msgstr "" msgid "&Mute" @@ -270,7 +291,7 @@ msgstr "" msgid "Reload previous image" msgstr "" -msgid "&Folder..." +msgid "&Folder…" msgstr "" msgid "Preferences" @@ -417,16 +438,16 @@ msgstr "" msgid "Joystick" msgstr "" -msgid "Joystick 1..." +msgid "Joystick 1…" msgstr "" -msgid "Joystick 2..." +msgid "Joystick 2…" msgstr "" -msgid "Joystick 3..." +msgid "Joystick 3…" msgstr "" -msgid "Joystick 4..." +msgid "Joystick 4…" msgstr "" msgid "Sound card #1:" @@ -516,10 +537,10 @@ msgstr "" msgid "Parallel port 4" msgstr "" -msgid "FD Controller:" +msgid "Floppy disk controller:" msgstr "" -msgid "CD-ROM Controller:" +msgid "CD-ROM controller:" msgstr "" msgid "Tertiary IDE Controller" @@ -528,10 +549,10 @@ msgstr "" msgid "Quaternary IDE Controller" msgstr "" -msgid "Hard disk" +msgid "Hard disk controllers" msgstr "" -msgid "SCSI" +msgid "SCSI controllers" msgstr "" msgid "Controller 1:" @@ -555,10 +576,10 @@ msgstr "" msgid "Firmware Version" msgstr "" -msgid "&New..." +msgid "&New…" msgstr "" -msgid "&Existing..." +msgid "&Existing…" msgstr "" msgid "&Remove" @@ -867,9 +888,6 @@ msgstr "" msgid "6-button gamepad" msgstr "" -msgid "Gravis PC GamePad" -msgstr "" - msgid "2-button flight yoke" msgstr "" @@ -897,51 +915,6 @@ msgstr "" msgid "Steering wheel (3-axis, 4-button)" msgstr "" -msgid "CH Flightstick" -msgstr "" - -msgid "CH Flightstick + CH Pedals" -msgstr "" - -msgid "CH Flightstick + CH Pedals Pro" -msgstr "" - -msgid "CH Flightstick Pro" -msgstr "" - -msgid "CH Flightstick Pro + CH Pedals" -msgstr "" - -msgid "CH Flightstick Pro + CH Pedals Pro" -msgstr "" - -msgid "CH Virtual Pilot" -msgstr "" - -msgid "CH Virtual Pilot + CH Pedals" -msgstr "" - -msgid "CH Virtual Pilot + CH Pedals Pro" -msgstr "" - -msgid "CH Virtual Pilot Pro" -msgstr "" - -msgid "CH Virtual Pilot Pro + CH Pedals" -msgstr "" - -msgid "CH Virtual Pilot Pro + CH Pedals Pro" -msgstr "" - -msgid "Microsoft SideWinder Pad" -msgstr "" - -msgid "Thrustmaster Flight Control System" -msgstr "" - -msgid "Thrustmaster FCS + Rudder Control System" -msgstr "" - msgid "Thrustmaster Formula T1/T2 with adapter" msgstr "" @@ -996,10 +969,16 @@ msgstr "" msgid "&File" msgstr "" -msgid "&New machine..." +msgid "&New machine…" msgstr "" -msgid "&Check for updates..." +msgid "New machine…" +msgstr "" + +msgid "New machine" +msgstr "" + +msgid "&Check for updates…" msgstr "" msgid "Exit" @@ -1170,7 +1149,7 @@ msgstr "" msgid "Use regular expressions in search box" msgstr "" -msgid "%1 machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" +msgid "%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" msgstr "" msgid "Add new system wizard" @@ -1251,25 +1230,22 @@ msgstr "" msgid "Enter the new display name (blank to reset)" msgstr "" -msgid "Change &display name..." -msgstr "" - -msgid "Context Menu" +msgid "Change &display name…" msgstr "" -msgid "&Open folder..." +msgid "&Open folder…" msgstr "" -msgid "Open p&rinter tray..." +msgid "Open p&rinter tray…" msgstr "" -msgid "Set &icon..." +msgid "Set &icon…" msgstr "" msgid "Select an icon" msgstr "" -msgid "C&lone..." +msgid "C&lone…" msgstr "" msgid "Virtual machine \"%1\" (%2) will be cloned into:" @@ -1356,7 +1332,7 @@ msgstr "" msgid "Search" msgstr "" -msgid "Searching for VMs..." +msgid "Searching for VMs…" msgstr "" msgid "Found %1" @@ -1392,10 +1368,10 @@ msgstr "" msgid "MFM/RLL or ESDI CD-ROM drives never existed" msgstr "" -msgid "Custom..." +msgid "Custom…" msgstr "" -msgid "Custom (large)..." +msgid "Custom (large)…" msgstr "" msgid "Add New Hard Disk" @@ -1515,21 +1491,6 @@ msgstr "" msgid "Could not fix VHD timestamp." msgstr "" -msgid "MFM/RLL" -msgstr "" - -msgid "XTA" -msgstr "" - -msgid "ESDI" -msgstr "" - -msgid "IDE" -msgstr "" - -msgid "ATAPI" -msgstr "" - msgid "CD-ROM %1 (%2): %3" msgstr "" @@ -1680,13 +1641,13 @@ msgstr "" msgid "About &Qt" msgstr "" -msgid "&MCA devices..." +msgid "&MCA devices…" msgstr "" msgid "Show non-&primary monitors" msgstr "" -msgid "Open screenshots &folder..." +msgid "Open screenshots &folder…" msgstr "" msgid "Appl&y fullscreen stretch mode when maximized" @@ -1707,7 +1668,7 @@ msgstr "" msgid "Clear image &history" msgstr "" -msgid "Create..." +msgid "Create…" msgstr "" msgid "Host CD/DVD Drive (%1)" @@ -1749,7 +1710,7 @@ msgstr "" msgid "Remove" msgstr "" -msgid "Browse..." +msgid "Browse…" msgstr "" msgid "Couldn't create OpenGL context." @@ -1839,7 +1800,7 @@ msgstr "" msgid "Serial port passthrough 4" msgstr "" -msgid "Renderer &options..." +msgid "Renderer &options…" msgstr "" msgid "PC/XT Keyboard" @@ -1893,7 +1854,7 @@ msgstr "" msgid "Default Baud rate" msgstr "" -msgid "[COM] Standard Hayes-compliant Modem" +msgid "Standard Hayes-compliant Modem" msgstr "" msgid "Roland MT-32 Emulation" @@ -1977,6 +1938,9 @@ msgstr "" msgid "Parallel port IRQ" msgstr "" +msgid "Hard disk" +msgstr "" + msgid "BIOS Revision" msgstr "" @@ -2052,9 +2016,6 @@ msgstr "" msgid "MIDI Clockout" msgstr "" -msgid "SoundFont" -msgstr "" - msgid "Output Gain" msgstr "" @@ -2847,9 +2808,6 @@ msgstr "" msgid "Toggle UI in fullscreen" msgstr "" -msgid "Screenshot" -msgstr "" - msgid "Release mouse pointer" msgstr "" @@ -2964,7 +2922,7 @@ msgstr "" msgid "Update check" msgstr "" -msgid "Checking for updates..." +msgid "Checking for updates…" msgstr "" msgid "86Box Update" @@ -3003,7 +2961,7 @@ msgstr "" msgid "Sharpness" msgstr "" -msgid "&CGA composite settings..." +msgid "&CGA composite settings…" msgstr "" msgid "CGA composite settings" @@ -3012,7 +2970,7 @@ msgstr "" msgid "Monitor EDID" msgstr "" -msgid "Export..." +msgid "Export…" msgstr "" msgid "Export EDID" @@ -3038,3 +2996,24 @@ msgstr "" msgid "Search:" msgstr "" + +msgid "Force interpretation" +msgstr "" + +msgid "Allow recompilation" +msgstr "" + +msgid "&Force interpretation" +msgstr "" + +msgid "&Allow recompilation" +msgstr "" + +msgid "&Fast forward" +msgstr "" + +msgid "Fast forward" +msgstr "" + +msgid "To change the system directory, stop all running machines." +msgstr "" diff --git a/src/qt/languages/ca-ES.po b/src/qt/languages/ca-ES.po new file mode 100644 index 00000000000..ad9dd6eb11d --- /dev/null +++ b/src/qt/languages/ca-ES.po @@ -0,0 +1,3025 @@ +msgid "" +msgstr "" +"PO-Revision-Date: 2025-11-29 00:34+0000\n" +"Last-Translator: OBattler \n" +"Language-Team: Catalan \n" +"Language: ca-ES\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.12.2\n" +"X-Language: ca_ES\n" +"X-Source-Language: en_US\n" + +msgid "&Action" +msgstr "&Acció" + +msgid "&Keyboard requires capture" +msgstr "&Teclat requereix captura" + +msgid "&Right CTRL is left ALT" +msgstr "CTRL &dret és ALT esquerre" + +msgid "&Hard reset" +msgstr "&Reiniciació completa" + +msgid "&Ctrl+Alt+Del" +msgstr "&Ctrl+Alt+Supr" + +msgid "Ctrl+Alt+&Esc" +msgstr "Ctrl+Alt+&Esc" + +msgid "&Pause" +msgstr "&Pausa" + +msgid "Pause" +msgstr "Pausa" + +msgid "Re&sume" +msgstr "Re&prendre" + +msgid "E&xit" +msgstr "&Surt" + +msgid "&View" +msgstr "&Visualitza" + +msgid "&Hide status bar" +msgstr "&Amaga la barra d'estat" + +msgid "Hide &toolbar" +msgstr "Amaga la &barra d'eines" + +msgid "&Resizeable window" +msgstr "Fi&nestra redimensionable" + +msgid "R&emember size && position" +msgstr "&Recorda grandària i posició" + +msgid "Remember size && position" +msgstr "Recorda grandària i posició" + +msgid "Re&nderer" +msgstr "Re&nderitzador" + +msgid "&Qt (Software)" +msgstr "&Qt (Programari)" + +msgid "Open&GL (3.0 Core)" +msgstr "Open&GL (3.0 Core)" + +msgid "&VNC" +msgstr "&VNC" + +msgid "Specify &dimensions…" +msgstr "E&specifica dimensions…" + +msgid "Force &4:3 display ratio" +msgstr "Força ràtio de visualització &4:3" + +msgid "&Window scale factor" +msgstr "&Factor de escalat de finestra" + +msgid "&0.5x" +msgstr "&0.5x" + +msgid "&1x" +msgstr "&1x" + +msgid "1.&5x" +msgstr "1.&5x" + +msgid "&2x" +msgstr "&2x" + +msgid "&3x" +msgstr "&3x" + +msgid "&4x" +msgstr "&4x" + +msgid "&5x" +msgstr "&5x" + +msgid "&6x" +msgstr "&6x" + +msgid "&7x" +msgstr "&7x" + +msgid "&8x" +msgstr "&8x" + +msgid "Fi<er method" +msgstr "&Mètode de filtració" + +msgid "&Nearest" +msgstr "&Més a prop" + +msgid "&Linear" +msgstr "&Lineal" + +msgid "Hi&DPI scaling" +msgstr "&Escalat alta densitat" + +msgid "&Fullscreen" +msgstr "&Pantalla sencera" + +msgid "Fullscreen &stretch mode" +msgstr "M&odalitat de estirament en la pantalla sencera" + +msgid "&Full screen stretch" +msgstr "&Estirament en la pantalla sencera" + +msgid "&4:3" +msgstr "&4:3" + +msgid "&Square pixels (Keep ratio)" +msgstr "&Píxels quadrats (Mantenir ràtio)" + +msgid "&Integer scale" +msgstr "&Escalat de valor enter" + +msgid "4:&3 Integer scale" +msgstr "Escalat de valor enter 4:&3" + +msgid "EGA/(S)&VGA settings" +msgstr "Configuració EGA/(S)&VGA" + +msgid "&Inverted VGA monitor" +msgstr "&Monitor VGA invertit" + +msgid "VGA screen &type" +msgstr "&Tipus de pantalla VGA" + +msgid "RGB &Color" +msgstr "&Colors RGB" + +msgid "RGB (no brown)" +msgstr "RGB (sense marró)" + +msgid "&RGB Grayscale" +msgstr "&RGB en escala de grisos" + +msgid "Generic RGBI color monitor" +msgstr "Monitor RGBI genèric a color" + +msgid "&Amber monitor" +msgstr "Monitor ambr&e" + +msgid "&Green monitor" +msgstr "Monitor &verd" + +msgid "&White monitor" +msgstr "Monitor &blanc" + +msgid "Grayscale &conversion type" +msgstr "Tipus de &conversió a l'escala de grisos" + +msgid "BT&601 (NTSC/PAL)" +msgstr "BT&601 (NTSC/PAL)" + +msgid "BT&709 (HDTV)" +msgstr "BT&709 (HDTV)" + +msgid "&Average" +msgstr "&Mitja" + +msgid "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" +msgstr "Overscan de CGA/PCjr/Tandy/E&GA/(S)VGA" + +msgid "Change contrast for &monochrome display" +msgstr "Canvia contrast per a la pantalla &monocromàtica" + +msgid "&Media" +msgstr "&Mitjans" + +msgid "&Tools" +msgstr "&Eines" + +msgid "&Settings…" +msgstr "&Configuració…" + +msgid "Settings…" +msgstr "Configuració…" + +msgid "&Update status bar icons" +msgstr "&Actualitza icones a la barra d'estat" + +msgid "Take s&creenshot" +msgstr "Desa captura de &pantalla" + +msgid "Take screenshot" +msgstr "Desa captura de pantalla" + +msgid "Take &raw screenshot" +msgstr "Desa captura en &brut de pantalla" + +msgid "Take raw screenshot" +msgstr "Desa captura en brut de pantalla" + +msgid "C&opy screenshot" +msgstr "C&opia captura de pantalla" + +msgid "Copy screenshot" +msgstr "Copia captura de pantalla" + +msgid "Copy r&aw screenshot" +msgstr "Copy captura en b&rut de pantalla" + +msgid "Copy raw screenshot" +msgstr "Copy captura en brut de pantalla" + +msgid "S&ound" +msgstr "S&o" + +msgid "&Preferences…" +msgstr "&Preferències…" + +msgid "Enable &Discord integration" +msgstr "Activa integració amb D&iscord" + +msgid "Sound &gain…" +msgstr "&Guany de so…" + +msgid "Begin trace" +msgstr "Inicia el rastreig" + +msgid "End trace" +msgstr "Acaba el rastreig" + +msgid "&Help" +msgstr "Aj&uda" + +msgid "&Documentation…" +msgstr "&Documentació…" + +msgid "&About 86Box…" +msgstr "&Quant al 86Box…" + +msgid "&New image…" +msgstr "&Nova imatge…" + +msgid "&Existing image…" +msgstr "Imatge &existent…" + +msgid "Existing image (&Write-protected)…" +msgstr "Imatge existent (&Protegit d'escriptura)…" + +msgid "&Record" +msgstr "&Enregistra" + +msgid "&Play" +msgstr "&Reprodueix" + +msgid "&Rewind to the beginning" +msgstr "&Rebobina a l'inici" + +msgid "&Fast forward to the end" +msgstr "&Avança ràpid al final" + +msgid "E&ject" +msgstr "E&xpolsa" + +msgid "&Image…" +msgstr "&Imatge…" + +msgid "E&xport to 86F…" +msgstr "E&xporta a 86F…" + +msgid "&Mute" +msgstr "&Silencia" + +msgid "E&mpty" +msgstr "&CDROM buit" + +msgid "Reload previous image" +msgstr "Recarrega imatge prèvia" + +msgid "&Folder…" +msgstr "&Carpeta…" + +msgid "Preferences" +msgstr "Preferències" + +msgid "Sound Gain" +msgstr "Guany de so" + +msgid "New Image" +msgstr "Nova imatge" + +msgid "Settings" +msgstr "Configuració" + +msgid "Specify Main Window Dimensions" +msgstr "Especifica dimensions de la finestra principal" + +msgid "OK" +msgstr "D'acord" + +msgid "Cancel" +msgstr "Anuŀla" + +msgid "&Default" +msgstr "&Per defecte" + +msgid "Language:" +msgstr "Idioma:" + +msgid "Gain" +msgstr "Guany" + +msgid "File name:" +msgstr "Nom de fitxer:" + +msgid "Disk size:" +msgstr "Mida del disc:" + +msgid "RPM mode:" +msgstr "Modalitat RPM:" + +msgid "Progress:" +msgstr "Progrés:" + +msgid "Width:" +msgstr "Amplada:" + +msgid "Height:" +msgstr "Alçada:" + +msgid "Lock to this size" +msgstr "Fixa a aquesta grandària" + +msgid "Machine type:" +msgstr "Tipus de màquina:" + +msgid "Machine:" +msgstr "Màquina:" + +msgid "Configure" +msgstr "Configura" + +msgid "CPU:" +msgstr "Processador:" + +msgid "CPU type:" +msgstr "Tipus del CPU:" + +msgid "Speed:" +msgstr "Velocitat:" + +msgid "Frequency:" +msgstr "Freqüència:" + +msgid "FPU:" +msgstr "FPU:" + +msgid "Wait states:" +msgstr "Estats de espera:" + +msgid "MB" +msgstr "MB" + +msgid "Memory:" +msgstr "Memòria:" + +msgid "Time synchronization" +msgstr "Sincronització de l'hora" + +msgid "Disabled" +msgstr "Desactivat" + +msgid "Enabled (local time)" +msgstr "Activat (hora local)" + +msgid "Enabled (UTC)" +msgstr "Activat (UTC)" + +msgid "Dynamic Recompiler" +msgstr "Recompilador dinàmic" + +msgid "CPU frame size" +msgstr "Mida de blocs de la CPU" + +msgid "Larger frames (less smooth)" +msgstr "Blocs més grans (menys suau)" + +msgid "Smaller frames (smoother)" +msgstr "Blocs més petits (més suau)" + +msgid "Video:" +msgstr "Vídeo:" + +msgid "Video #2:" +msgstr "Vídeo 2:" + +msgid "Voodoo 1 or 2 Graphics" +msgstr "Gràfics Voodoo 1 o 2" + +msgid "IBM 8514/A Graphics" +msgstr "Gràfics IBM 8514/A" + +msgid "XGA Graphics" +msgstr "Gràfics XGA" + +msgid "IBM PS/55 Display Adapter Graphics" +msgstr "Adaptador de gràfics de pantalla IBM PS/55" + +msgid "Keyboard:" +msgstr "Teclat:" + +msgid "Keyboard" +msgstr "Teclat" + +msgid "Mouse:" +msgstr "Ratolí:" + +msgid "Mouse" +msgstr "Ratolí" + +msgid "Joystick:" +msgstr "Comandament:" + +msgid "Joystick" +msgstr "Joystick" + +msgid "Joystick 1…" +msgstr "Joystick 1…" + +msgid "Joystick 2…" +msgstr "Joystick 2…" + +msgid "Joystick 3…" +msgstr "Joystick 3…" + +msgid "Joystick 4…" +msgstr "Joystick 4…" + +msgid "Sound card #1:" +msgstr "Targeta de so núm. 1:" + +msgid "Sound card #2:" +msgstr "Targeta de so núm. 2:" + +msgid "Sound card #3:" +msgstr "Targeta de so núm. 3:" + +msgid "Sound card #4:" +msgstr "Targeta de so núm. 4:" + +msgid "MIDI Out Device:" +msgstr "Dispositiu MIDI de sortida:" + +msgid "MIDI In Device:" +msgstr "Dispositiu MIDI d'entrada:" + +msgid "MIDI Out:" +msgstr "Sortida MIDI:" + +msgid "Standalone MPU-401" +msgstr "MPU-401 independent" + +msgid "Use FLOAT32 sound" +msgstr "Utilitza so FLOAT32" + +msgid "FM synth driver" +msgstr "Manejador de síntesi FM" + +msgid "Nuked (more accurate)" +msgstr "Nuked (més precís)" + +msgid "YMFM (faster)" +msgstr "YMFM (més ràpid)" + +msgid "COM1 Device:" +msgstr "Dispositiu COM1:" + +msgid "COM2 Device:" +msgstr "Dispositiu COM2:" + +msgid "COM3 Device:" +msgstr "Dispositiu COM3:" + +msgid "COM4 Device:" +msgstr "Dispositiu COM4:" + +msgid "LPT1 Device:" +msgstr "Dispositiu LPT1:" + +msgid "LPT2 Device:" +msgstr "Dispositiu LPT2:" + +msgid "LPT3 Device:" +msgstr "Dispositiu LPT3:" + +msgid "LPT4 Device:" +msgstr "Dispositiu LPT4:" + +msgid "Internal LPT ECP DMA:" +msgstr "DMA de ECP de l'LPT intern:" + +msgid "Serial port 1" +msgstr "Port sèrie 1" + +msgid "Serial port 2" +msgstr "Port sèrie 2" + +msgid "Serial port 3" +msgstr "Port sèrie 3" + +msgid "Serial port 4" +msgstr "Port sèrie 4" + +msgid "Parallel port 1" +msgstr "Port paralel 1" + +msgid "Parallel port 2" +msgstr "Port paralel 2" + +msgid "Parallel port 3" +msgstr "Port paralel 3" + +msgid "Parallel port 4" +msgstr "Port paralel 4" + +msgid "Floppy disk controller:" +msgstr "Controladora de disquets:" + +msgid "CD-ROM controller:" +msgstr "Controladora de CD-ROM:" + +msgid "Tertiary IDE Controller" +msgstr "Controlador IDE terciari" + +msgid "Quaternary IDE Controller" +msgstr "Controlador IDE quaternari" + +msgid "Hard disk controllers" +msgstr "Controladores de disc dur" + +msgid "SCSI controllers" +msgstr "Controladores SCSI" + +msgid "Controller 1:" +msgstr "Controladora 1:" + +msgid "Controller 2:" +msgstr "Controladora 2:" + +msgid "Controller 3:" +msgstr "Controladora 3:" + +msgid "Controller 4:" +msgstr "Controladora 4:" + +msgid "Cassette" +msgstr "Cinta" + +msgid "Hard disks:" +msgstr "Discs durs:" + +msgid "Firmware Version" +msgstr "Versió del firmware" + +msgid "&New…" +msgstr "&Nou…" + +msgid "&Existing…" +msgstr "&Existent…" + +msgid "&Remove" +msgstr "&Suprimir" + +msgid "Bus:" +msgstr "Bus:" + +msgid "Channel:" +msgstr "Canal:" + +msgid "ID:" +msgstr "ID:" + +msgid "Sectors:" +msgstr "Sectors:" + +msgid "Heads:" +msgstr "Cabeçals:" + +msgid "Cylinders:" +msgstr "Cilindres:" + +msgid "Size (MB):" +msgstr "Mida (MB):" + +msgid "Type:" +msgstr "Tipus:" + +msgid "Image Format:" +msgstr "Format d'imatge:" + +msgid "Block Size:" +msgstr "Mida de bloc:" + +msgid "Floppy drives:" +msgstr "Unitats de disquet:" + +msgid "Turbo timings" +msgstr "Velocitat turbo" + +msgid "Check BPB" +msgstr "Verificar BPB" + +msgid "CD-ROM drives:" +msgstr "Unitats de CD-ROM:" + +msgid "MO drives:" +msgstr "Unitats MO:" + +msgid "MO:" +msgstr "MO:" + +msgid "Removable disks:" +msgstr "Discs extraïbles:" + +msgid "Removable disk drives:" +msgstr "Unitats de disc extraïble:" + +msgid "ZIP 250" +msgstr "ZIP 250" + +msgid "ISA RTC:" +msgstr "ISA RTC:" + +msgid "ISA Memory Expansion" +msgstr "Expansió de memòria ISA" + +msgid "ISA ROM Cards" +msgstr "Targetes ROM ISA" + +msgid "Card 1:" +msgstr "Targeta 1:" + +msgid "Card 2:" +msgstr "Targeta 2:" + +msgid "Card 3:" +msgstr "Targeta 3:" + +msgid "Card 4:" +msgstr "Targeta 4:" + +msgid "Generic ISA ROM Board" +msgstr "Targeta ROM ISA genèrica" + +msgid "Generic Dual ISA ROM Board" +msgstr "Targeta ROM ISA genèrica doble" + +msgid "Generic Quad ISA ROM Board" +msgstr "Targeta ROM ISA genèrica quàdruple" + +msgid "ISABugger device" +msgstr "Dispositiu ISABugger" + +msgid "POST card" +msgstr "Targeta POST" + +msgid "Error" +msgstr "Error" + +msgid "Fatal error" +msgstr "Error fatal" + +msgid " - PAUSED" +msgstr " - EN PAUSA" + +msgid "Speed" +msgstr "Velocitat" + +msgid "Removable disk %1 (%2): %3" +msgstr "Disc extraïble %1 (%2): %3" + +msgid "&Removable disk %1 (%2): %3" +msgstr "&Disc extraïble %1 (%2): %3" + +msgid "Removable disk images" +msgstr "Imatges de disc extraïble" + +msgid "Image %1" +msgstr "Imatge %1" + +msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." +msgstr "El 86Box no ha pogut trobar cap de imatge ROM utilitzable.\n\nSi us plau, descarregueu un conjunt de ROMs i extraieu-les al directori \"roms\"." + +msgid "(empty)" +msgstr "(buit)" + +msgid "All files" +msgstr "Tots els fitxers" + +msgid "Turbo" +msgstr "Turbo" + +msgid "On" +msgstr "Activat" + +msgid "Off" +msgstr "Desactivat" + +msgid "All images" +msgstr "Totes les imatges" + +msgid "Basic sector images" +msgstr "Imatges bàsiques de sector" + +msgid "Surface images" +msgstr "Imatges de superfície" + +msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." +msgstr "La màquina \"%hs\" no està disponible a causa de les ROMs faltants al directori roms/machines. Canviant a una màquina disponible." + +msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." +msgstr "La tarjeta de vídeo \"%hs\" no està disponible a causa de les ROMs faltants al directori roms/video. Canviant a una tarjeta de video disponible." + +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "La tarjeta de vídeo 2 \"%hs\" no està disponible a causa de les ROMs faltants al directori roms/video. Desactivant la segona targeta de vídeo." + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "El dispositiu \"%hs\" no està disponible a causa de les ROMs faltants. Ignorant el dispositiu." + +msgid "Machine" +msgstr "Màquina" + +msgid "Display" +msgstr "Pantalla" + +msgid "Input devices" +msgstr "Dispositius de entrada" + +msgid "Sound" +msgstr "So" + +msgid "Network" +msgstr "Xarxa" + +msgid "Ports (COM & LPT)" +msgstr "Ports (COM i LPT)" + +msgid "Ports" +msgstr "Ports" + +msgid "Serial ports:" +msgstr "Ports sèrie:" + +msgid "Parallel ports:" +msgstr "Puerts paralels:" + +msgid "Storage controllers" +msgstr "Controladors de emmagatzematge" + +msgid "Hard disks" +msgstr "Discs durs" + +msgid "Disks:" +msgstr "Discs:" + +msgid "Floppy:" +msgstr "Disquet:" + +msgid "Controllers:" +msgstr "Controladors:" + +msgid "Floppy & CD-ROM drives" +msgstr "Disquets i unitats de CD-ROM" + +msgid "Other removable devices" +msgstr "Altres dispositius extraïbles" + +msgid "Other peripherals" +msgstr "Altres perifèrics" + +msgid "Other devices" +msgstr "Altres dispositius" + +msgid "Click to capture mouse" +msgstr "Feu clic per capturar el ratolí" + +msgid "Press %1 to release mouse" +msgstr "Premeu %1 per alliberar el ratolí" + +msgid "Press %1 or middle button to release mouse" +msgstr "Premeu %1 o bé el botó central per alliberar el ratolí" + +msgid "Bus" +msgstr "Bus" + +msgid "File" +msgstr "Fitxer" + +msgid "C" +msgstr "C" + +msgid "H" +msgstr "H" + +msgid "S" +msgstr "S" + +msgid "KB" +msgstr "KB" + +msgid "Default" +msgstr "Per defecte" + +msgid "%1 Wait state(s)" +msgstr "%1 estat(s) de espera" + +msgid "Type" +msgstr "Tipus" + +msgid "No PCap devices found" +msgstr "No s'ha trobat cap dispositiu PCap" + +msgid "Invalid PCap device" +msgstr "Dispositiu PCap invàlid" + +msgid "Generic paddle controller(s)" +msgstr "Controlador(s) de rem genèric(s)" + +msgid "2-axis, 1-button joystick(s)" +msgstr "Joystick(s) de 2 eixos, 1 botons" + +msgid "2-axis, 2-button joystick(s)" +msgstr "Joystick(s) de 2 eixos, 2 botons" + +msgid "2-axis, 3-button joystick" +msgstr "Joystick de 2 eixos, 3 botons" + +msgid "2-axis, 4-button joystick" +msgstr "Joystick de 2 eixos, 4 botons" + +msgid "2-axis, 6-button joystick" +msgstr "Joystick de 2 eixos, 6 botons" + +msgid "2-axis, 8-button joystick" +msgstr "Joystick de 2 eixos, 8 botons" + +msgid "3-axis, 2-button joystick" +msgstr "Joystick de 3 eixos, 2 botons" + +msgid "3-axis, 3-button joystick" +msgstr "Joystick de 3 eixos, 3 botons" + +msgid "3-axis, 4-button joystick" +msgstr "Joystick de 3 eixos, 4 botons" + +msgid "4-axis, 2-button joystick" +msgstr "Joystick de 4 eixos, 2 botons" + +msgid "4-axis, 3-button joystick" +msgstr "Joystick de 4 eixos, 3 botons" + +msgid "4-axis, 4-button joystick" +msgstr "Joystick de 4 eixos, 4 botons" + +msgid "2-button gamepad(s)" +msgstr "Comandament(s) de joc de 2 botons" + +msgid "3-button gamepad" +msgstr "Comandament de joc de 3 botons" + +msgid "4-button gamepad" +msgstr "Comandament de joc de 4 botons" + +msgid "6-button gamepad" +msgstr "Comandament de joc de 6 botons" + +msgid "2-button flight yoke" +msgstr "Volant d'avió de 2 botons" + +msgid "3-button flight yoke" +msgstr "Volant d'avió de 3 botons" + +msgid "4-button flight yoke" +msgstr "Volant d'avió de 4 botons" + +msgid "2-button flight yoke with throttle" +msgstr "Volant d'avió de 2 botones amb accelerador" + +msgid "3-button flight yoke with throttle" +msgstr "Volant d'avió de 3 botones amb accelerador" + +msgid "4-button flight yoke with throttle" +msgstr "Volant d'avió de 4 botones amb accelerador" + +msgid "Steering wheel (3-axis, 2-button)" +msgstr "Volant (de 3 eixos, 2 botons)" + +msgid "Steering wheel (3-axis, 3-button)" +msgstr "Volant (de 3 eixos, 3 botons)" + +msgid "Steering wheel (3-axis, 4-button)" +msgstr "Volant (de 3 eixos, 4 botons)" + +msgid "Thrustmaster Formula T1/T2 with adapter" +msgstr "Thrustmaster Formula T1/T2 amb adaptador" + +msgid "Thrustmaster Formula T1/T2 without adapter" +msgstr "Thrustmaster Formula T1/T2 sense adaptador" + +msgid "None" +msgstr "Cap" + +msgid "%1 MB (CHS: %2, %3, %4)" +msgstr "%1 MB (CHS: %2, %3, %4)" + +msgid "Floppy %1 (%2): %3" +msgstr "Disquet %1 (%2): %3" + +msgid "&Floppy %1 (%2): %3" +msgstr "&Disquet %1 (%2): %3" + +msgid "Advanced sector images" +msgstr "Imatges avançades de sector" + +msgid "Flux images" +msgstr "Imatges de fluix" + +msgid "Are you sure you want to hard reset the emulated machine?" +msgstr "Esteu segurs de que voleu fer una reinicialització completa de la màquina emulada?" + +msgid "Are you sure you want to exit 86Box?" +msgstr "Esteu segurs de que voleu tancar al 86Box?" + +msgid "Unable to initialize Ghostscript" +msgstr "No fou possible inicialitzar el Ghostscript" + +msgid "Unable to initialize GhostPCL" +msgstr "No fou possible inicialitzar el GhostPCL" + +msgid "MO %1 (%2): %3" +msgstr "MO %1 (%2): %3" + +msgid "&MO %1 (%2): %3" +msgstr "&MO %1 (%2): %3" + +msgid "MO images" +msgstr "Imatges de MO" + +msgid "Welcome to 86Box!" +msgstr "Benvinguts al 86Box!" + +msgid "Internal device" +msgstr "Dispositiu intern" + +msgid "&File" +msgstr "&Fitxer" + +msgid "&New machine…" +msgstr "&Nova màquina…" + +msgid "New machine…" +msgstr "Nova màquina…" + +msgid "New machine" +msgstr "Nova màquina" + +msgid "&Check for updates…" +msgstr "&Comprova actualitzacions…" + +msgid "Exit" +msgstr "Sortir" + +msgid "No ROMs found" +msgstr "No s'han trobat ROMs" + +msgid "Do you want to save the settings?" +msgstr "Voleu desar les configuracions?" + +msgid "This will hard reset the emulated machine." +msgstr "Això causarà una reinicialització completa de la màquina emulada." + +msgid "Save" +msgstr "Desa" + +msgid "About %1" +msgstr "Quant al %1" + +msgid "An emulator of old computers\n\nAuthors: Miran Grča (OBattler), RichardG867, Jasmine Iwanek, TC1995, coldbrewed, Teemu Korhonen (Manaatti), Joakim L. Gilje, Adrien Moulin (elyosh), Daniel Balsom (gloriouscow), Cacodemon345, Fred N. van Kempen (waltje), Tiseno100, reenigne, and others.\n\nWith previous core contributions from Sarah Walker, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." +msgstr "Un emulador d'ordinadors antics\n\nAutors: Miran Grča (OBattler), RichardG867, Jasmine Iwanek, TC1995, coldbrewed, Teemu Korhonen (Manaatti), Joakim L. Gilje, Adrien Moulin (elyosh), Daniel Balsom (gloriouscow), Cacodemon345, Fred N. van Kempen (waltje), Tiseno100, reenigne, i altres.\n\nAmb contribucions anteriors de Sarah Walker, leilei, JohnElliott, greatpsycho i altres.\n\nPublicat sota la GNU General Public License versió 2 o posterior. Veieu LICENSE per a més informació." + +msgid "Hardware not available" +msgstr "Equip no disponible" + +msgid "Make sure %1 is installed and that you are on a %1-compatible network connection." +msgstr "Assegureu-vos de que %1 està instal·lat i de que esteu en una connexió de xarxa compatible amb %1." + +msgid "Invalid configuration" +msgstr "Configuració invàlida" + +msgid "%1 is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." +msgstr "%1 és imprescindible per la conversió automàtica de fitxers PostScript a PDF.\n\nQualsevol document enviat a la impressora genèrica PostScript es desarà com a fitxer PostScript (.ps)." + +msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files." +msgstr "%1 és imprescindible per la conversió automàtica de fitxers PCL a PDF.\n\nQualsevol document enviat a la impressora genèrica PCL es desarà com a fitxer Printer Command Language (.pcl)." + +msgid "Don't show this message again" +msgstr "No tornis a mostrar aquest missatge" + +msgid "Don't exit" +msgstr "No sortir" + +msgid "Reset" +msgstr "Reinicialitza" + +msgid "Don't reset" +msgstr "No reinicialitzis" + +msgid "CD-ROM images" +msgstr "Imatges de CD-ROM" + +msgid "%1 Device Configuration" +msgstr "Configuració de dispositiu %1" + +msgid "Monitor in sleep mode" +msgstr "Monitor en suspens" + +msgid "GLSL shaders" +msgstr "Shaders GLSL" + +msgid "You are loading an unsupported configuration" +msgstr "Esteu carregant una configuració no suportada" + +msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." +msgstr "La filtració del tipus de CPU basat en la màquina sel·leccionada està desactivada per a aquesta màquina.\n\nAixò fa possible sel·leccionar una CPU que sigui incompatible amb aquesta màquina. Tanmateix, poden aparèixer incompatibilitats amb la BIOS de la màquina o altres programes.\n\nActivar esta configuració no està oficialment suportat i qualsevol report de error pot ser tancat com a invàlid." + +msgid "Continue" +msgstr "Continua" + +msgid "Cassette: %1" +msgstr "Cinta: %1" + +msgid "C&assette: %1" +msgstr "C&inta: %1" + +msgid "Cassette images" +msgstr "Imatges de cinta" + +msgid "Cartridge %1: %2" +msgstr "Cartutx %1: %2" + +msgid "Car&tridge %1: %2" +msgstr "Car&tutx %1: %2" + +msgid "Cartridge images" +msgstr "Imatges de cartutx" + +msgid "Resume execution" +msgstr "Reprendre la execució" + +msgid "Pause execution" +msgstr "Metre en pausa la execució" + +msgid "Ctrl+Alt+Del" +msgstr "Ctrl+Alt+Del" + +msgid "Press Ctrl+Alt+Del" +msgstr "Prémer Ctrl+Alt+Supr" + +msgid "Press Ctrl+Alt+Esc" +msgstr "Prémer Ctrl+Alt+Esc" + +msgid "Hard reset" +msgstr "Reiniciació completa" + +msgid "Force shutdown" +msgstr "Apagada forçada" + +msgid "Start" +msgstr "Inicia" + +msgid "&Force shutdown" +msgstr "&Apagada forçada" + +msgid "&Start" +msgstr "&Inicir" + +msgid "Not running" +msgstr "No en execució" + +msgid "Running" +msgstr "En exeució" + +msgid "Paused" +msgstr "En pausa" + +msgid "Waiting" +msgstr "En espera" + +msgid "Powered Off" +msgstr "Apagat" + +msgid "%n running" +msgstr "%n en execució" + +msgid "%n paused" +msgstr "%n en pausa" + +msgid "%n waiting" +msgstr "%n en espera" + +msgid "%1 total" +msgstr "%1 total" + +msgid "VMs: %1" +msgstr "MV: %1" + +msgid "System Directory:" +msgstr "Directori del sistema:" + +msgid "Choose directory" +msgstr "Escollir directori" + +msgid "Choose configuration file" +msgstr "Escollir fitxer de configuració" + +msgid "86Box configuration files (86box.cfg)" +msgstr "Fitxers de configuració de 86Box (86box.cfg)" + +msgid "Configuration read failed" +msgstr "Error en llegir la configuració" + +msgid "Unable to open the selected configuration file for reading: %1" +msgstr "No fou possible obrir el fitxer de configuració seleccionat per llegir: %1" + +msgid "Use regular expressions in search box" +msgstr "Utilitzeu expressions regulars a la caixa de cerca" + +msgid "%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" +msgstr "%n màquina(es) són actives en aquest moment. Segur que voleu sortir de l'administrador de MV?" + +msgid "Add new system wizard" +msgstr "Auxiliar d'addició de un nou sistema" + +msgid "Introduction" +msgstr "Introducció" + +msgid "This will help you add a new system to 86Box." +msgstr "Aquest us ajudará a afegir un nou sistema al 86Box." + +msgid "New configuration" +msgstr "Nova configuració" + +msgid "Complete" +msgstr "Completar" + +msgid "The wizard will now launch the configuration for the new system." +msgstr "L'auxiliar ara executarà la configuració pel nou sistema." + +msgid "Use existing configuration" +msgstr "Utilitza una configuració existent" + +msgid "Type some notes here" +msgstr "Escriviu algunes notes aquí" + +msgid "Paste the contents of the existing configuration file into the box below." +msgstr "Enganxa el contingut del fitxer de configuració existent en la caixa de sota." + +msgid "Load configuration from file" +msgstr "Carrega la configuració a partir d'un fitxer" + +msgid "System name" +msgstr "Nom del sistema" + +msgid "System name:" +msgstr "Nom del sistema:" + +msgid "System name cannot contain certain characters" +msgstr "El nom del sistema no pot contenir alguns caràcters" + +msgid "System name already exists" +msgstr "El nom del sistema ja existeix" + +msgid "Please enter a directory for the system" +msgstr "Si us plau, escriviu un directori per el sistema" + +msgid "Directory does not exist" +msgstr "El directori no existeix" + +msgid "A new directory for the system will be created in the selected directory above" +msgstr "Un nou directori per al sistema serà creat en el directori escollit a dalt" + +msgid "System location:" +msgstr "Ubicació del sistema:" + +msgid "System name and location" +msgstr "Nom i ubicació del sistema" + +msgid "Enter the name of the system and choose the location" +msgstr "Escriviu el nom del sistema i escolliu la ubicació" + +msgid "Enter the name of the system" +msgstr "Escriviu el nome del sistema" + +msgid "Please enter a system name" +msgstr "Si us plau, escriviu un nom del sistema" + +msgid "Display name (optional):" +msgstr "Nom mostrat (optatiu):" + +msgid "Display name:" +msgstr "Nom mostrat:" + +msgid "Set display name" +msgstr "Establir nom mostrat" + +msgid "Enter the new display name (blank to reset)" +msgstr "Escriviu el nou nom mostrat (buit per restablir)" + +msgid "Change &display name…" +msgstr "Canvia nom &mostrat…" + +msgid "&Open folder…" +msgstr "&Obre carpeta…" + +msgid "Open p&rinter tray…" +msgstr "Obre safata de la &impressora…" + +msgid "Set &icon…" +msgstr "Estableix &icona…" + +msgid "Select an icon" +msgstr "Tria una icona" + +msgid "C&lone…" +msgstr "C&lona…" + +msgid "Virtual machine \"%1\" (%2) will be cloned into:" +msgstr "La màquina virtual \"%1\" (%2) serà clonada a:" + +msgid "Directory %1 already exists" +msgstr "El directori %1 ja existeix" + +msgid "You cannot use the following characters in the name: %1" +msgstr "No es pot utilitzar els seguints caràcters en el nom: %1" + +msgid "Clone" +msgstr "Clona" + +msgid "Failed to create directory for cloned VM" +msgstr "Error en crear el directori per a la MV clonada" + +msgid "Failed to clone VM." +msgstr "Error en clonar la VM." + +msgid "Directory in use" +msgstr "Directori en ús" + +msgid "The selected directory is already in use. Please select a different directory." +msgstr "El directori escollit ja està en ùs. Si us plau, escolliu un altre directori." + +msgid "Create directory failed" +msgstr "Error en crear el directori" + +msgid "Unable to create the directory for the new system" +msgstr "No fou possible crear el directori pel nou sistema" + +msgid "Configuration write failed" +msgstr "Error en escriure la configuració" + +msgid "Unable to open the configuration file at %1 for writing" +msgstr "No fou possible obrir el fitxer de configuració en %1 per escriure" + +msgid "Error adding system" +msgstr "Error en afegir el sistema" + +msgid "Remove directory failed" +msgstr "Error en suprimir el directori" + +msgid "Some files in the machine's directory were unable to be deleted. Please delete them manually." +msgstr "No fou possible suprimir alguns fitxers al directori de la màquina. Si us plau, suprimiu-los manualment." + +msgid "Build" +msgstr "Compilació" + +msgid "Version" +msgstr "Versió" + +msgid "An update to 86Box is available: %1 %2" +msgstr "Està disponible una actualització pel 86Box: %1 %2" + +msgid "An error has occurred while checking for updates: %1" +msgstr "S'ha produït un error en verificar les actualitzacions: %1" + +msgid "An update to 86Box is available!" +msgstr "Una actualització pel 86Box està disponible!" + +msgid "Warning" +msgstr "Atenció" + +msgid "&Kill" +msgstr "&Finalitza forçosament" + +msgid "Killing a virtual machine can cause data loss. Only do this if the 86Box process gets stuck.\n\nDo you really wish to kill the virtual machine \"%1\"?" +msgstr "Finalitzar forçosament la màquina virtual pot causar la pèrdua de dades. Només feu-ho si el procés del 86Box s'ha blocat.\n\n¿Realment voleu finalitzar forçosament la màquina virtual \"%1\"?" + +msgid "&Delete" +msgstr "&Suprimir" + +msgid "Do you really want to delete the virtual machine \"%1\" and all its files? This action cannot be undone!" +msgstr "Realment voleu suprimir la màquina virtual \"%1\" i tots els seus fitxers? Aquesta acció no es pot desfer!" + +msgid "Show &config file" +msgstr "Mostra fitxer de &configuració" + +msgid "No screenshot" +msgstr "Sense captures de pantalla" + +msgid "Search" +msgstr "Cerca" + +msgid "Searching for VMs…" +msgstr "Cerca per MV…" + +msgid "Found %1" +msgstr "%1 trobada" + +msgid "System" +msgstr "Sistema" + +msgid "Storage" +msgstr "Emmagatzematge" + +msgid "Disk %1:" +msgstr "Disc %1:" + +msgid "No disks" +msgstr "Sense disc" + +msgid "Audio" +msgstr "So" + +msgid "Audio:" +msgstr "So:" + +msgid "ACPI shutdown" +msgstr "Apagada ACPI" + +msgid "ACP&I shutdown" +msgstr "Apagada ACP&I" + +msgid "Hard disk (%1)" +msgstr "Disc dur (%1)" + +msgid "MFM/RLL or ESDI CD-ROM drives never existed" +msgstr "Les unitats de CD-ROM MFM/RLL o bé ESDI no han existit" + +msgid "Custom…" +msgstr "Personalitzada…" + +msgid "Custom (large)…" +msgstr "Personalitzada (gran)…" + +msgid "Add New Hard Disk" +msgstr "Afegeix nou disc dur" + +msgid "Add Existing Hard Disk" +msgstr "Afegeix disc dur existent" + +msgid "HDI disk images cannot be larger than 4 GB." +msgstr "Les imatges de disc HDI no poden superar els 4 GB." + +msgid "Disk images cannot be larger than 127 GB." +msgstr "Les imatges de disc no poden superar els 127 GB." + +msgid "Hard disk images" +msgstr "Imatges de disc dur" + +msgid "Unable to read file" +msgstr "No s'ha pogut llegir el fitxer" + +msgid "Unable to write file" +msgstr "No s'ha pogut escriure el fitxer" + +msgid "HDI or HDX images with a sector size other than 512 are not supported." +msgstr "Les imatges HDI o bé HDX amb una mida de sector diferent a 512 no estan suportades." + +msgid "Disk image file already exists" +msgstr "La imatge de disc ja existeix" + +msgid "Please specify a valid file name." +msgstr "Si us plau, especifiqueu un nom de fitxer vàlid." + +msgid "Disk image created" +msgstr "Imatge de disc creada" + +msgid "Make sure the file exists and is readable." +msgstr "Assegureu-vos que el fitxer existeix i és llegible." + +msgid "Make sure the file is being saved to a writable directory." +msgstr "Assegureu-vos que el fitxer s'està desant a un directori amb permís de escirptura." + +msgid "Disk image too large" +msgstr "Imatge de disc massa gran" + +msgid "Remember to partition and format the newly-created drive." +msgstr "Recordeu de particionar i formatar la nova unitat." + +msgid "The selected file will be overwritten. Are you sure you want to use it?" +msgstr "El fitxer triat se sobreescriurà. Esteu segurs de que voleu utilitzar-lo?" + +msgid "Unsupported disk image" +msgstr "Imatge de disc no suportada" + +msgid "Overwrite" +msgstr "Sobreescriu" + +msgid "Don't overwrite" +msgstr "No sobreescriguis" + +msgid "Raw image" +msgstr "Imatge en brut" + +msgid "HDI image" +msgstr "Imatge HDI" + +msgid "HDX image" +msgstr "Imatge HDX" + +msgid "Fixed-size VHD" +msgstr "VHD de mida fixa" + +msgid "Dynamic-size VHD" +msgstr "VHD de mida dinàmica" + +msgid "Differencing VHD" +msgstr "VHD diferencial" + +msgid "(N/A)" +msgstr "(Cap)" + +msgid "Raw image (.img)" +msgstr "Imatge en brut (.img)" + +msgid "HDI image (.hdi)" +msgstr "Imatge HDI (.hdi)" + +msgid "HDX image (.hdx)" +msgstr "Imatge HDX (.hdx)" + +msgid "Fixed-size VHD (.vhd)" +msgstr "VHD de mida fixa (.vhd)" + +msgid "Dynamic-size VHD (.vhd)" +msgstr "VHD de mida dinàmica (.vhd)" + +msgid "Differencing VHD (.vhd)" +msgstr "VHD diferencial (.vhd)" + +msgid "Large blocks (2 MB)" +msgstr "Blocs grans (2 MB)" + +msgid "Small blocks (512 KB)" +msgstr "Blocs petits (512 KB)" + +msgid "VHD files" +msgstr "Fitxers VHD" + +msgid "Select the parent VHD" +msgstr "Escolliu el VHD pare" + +msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" +msgstr "Això podria significar que la imatge pare es va modificar després de que es creés la imatge diferencial.\n\nTambé pot passar si les imatges han sigut mogudes o copiades, o a causa d'un error all programa que va crear aquest disc.\n\nVoleu corregir les marques de temps?" + +msgid "Parent and child disk timestamps do not match" +msgstr "Les marques de temps del pare e fill no coincideixen" + +msgid "Could not fix VHD timestamp." +msgstr "No ha sigut possible corregir la marca de temps del VHD." + +msgid "CD-ROM %1 (%2): %3" +msgstr "CD-ROM %1 (%2): %3" + +msgid "&CD-ROM %1 (%2): %3" +msgstr "&CD-ROM %1 (%2): %3" + +msgid "160 KB" +msgstr "160 KB" + +msgid "180 KB" +msgstr "180 KB" + +msgid "320 KB" +msgstr "320 KB" + +msgid "360 KB" +msgstr "360 KB" + +msgid "640 KB" +msgstr "640 KB" + +msgid "720 KB" +msgstr "720 KB" + +msgid "1.2 MB" +msgstr "1,2 MB" + +msgid "1.25 MB" +msgstr "1,25 MB" + +msgid "1.44 MB" +msgstr "1,44 MB" + +msgid "DMF (cluster 1024)" +msgstr "DMF (clúster 1024)" + +msgid "DMF (cluster 2048)" +msgstr "DMF (clúster 2048)" + +msgid "2.88 MB" +msgstr "2,88 MB" + +msgid "ZIP 100" +msgstr "ZIP 100" + +msgid "3.5\" 128 MB (ISO 10090)" +msgstr "3,5\" 128 MB (ISO 10090)" + +msgid "3.5\" 230 MB (ISO 13963)" +msgstr "3,5\" 230 MB (ISO 13963)" + +msgid "3.5\" 540 MB (ISO 15498)" +msgstr "3,5\" 540 MB (ISO 15498)" + +msgid "3.5\" 640 MB (ISO 15498)" +msgstr "3,5\" 640 MB (ISO 15498)" + +msgid "3.5\" 1.3 GB (GigaMO)" +msgstr "3,5\" 1.3 GB (GigaMO)" + +msgid "3.5\" 2.3 GB (GigaMO 2)" +msgstr "3,5\" 2.3 GB (GigaMO 2)" + +msgid "5.25\" 600 MB" +msgstr "5,25\" 600 MB" + +msgid "5.25\" 650 MB" +msgstr "5,25\" 650 MB" + +msgid "5.25\" 1 GB" +msgstr "5,25\" 1 GB" + +msgid "5.25\" 1.3 GB" +msgstr "5,25\" 1.3 GB" + +msgid "Perfect RPM" +msgstr "RPM perfectes" + +msgid "1% below perfect RPM" +msgstr "1% per sota dels RPM perfectes" + +msgid "1.5% below perfect RPM" +msgstr "1.5% per sota dels RPM perfectes" + +msgid "2% below perfect RPM" +msgstr "2% per sota dels RPM perfectes" + +msgid "(System Default)" +msgstr "(Per defecte del sistema)" + +msgid "Failed to initialize network driver" +msgstr "No fou possible iniciaitzar el controlador de xarxa" + +msgid "The network configuration will be switched to the null driver" +msgstr "La configuració de xarxa es canviarà al controlador nul" + +msgid "Mouse sensitivity:" +msgstr "Sensitivitat del ratolí:" + +msgid "Select media images from program working directory" +msgstr "Trieu imatges de mitjans del directori de treball del programa" + +msgid "PIT mode:" +msgstr "Modalitat PIT:" + +msgid "Auto" +msgstr "Automàtica" + +msgid "Slow" +msgstr "Lenta" + +msgid "Fast" +msgstr "Rápida" + +msgid "&Auto-pause on focus loss" +msgstr "Pa&usa automàtica en perdre el focus" + +msgid "WinBox is no longer supported" +msgstr "El WinBox ja no és suportat" + +msgid "Development of the WinBox manager stopped in 2022 due to a lack of maintainers. As we direct our efforts towards making 86Box even better, we have made the decision to no longer support WinBox as a manager.\n\nNo further updates will be provided through WinBox, and you may encounter incorrect behavior should you continue using it with newer versions of 86Box. Any bug reports related to WinBox behavior will be closed as invalid.\n\nGo to 86box.net for a list of other managers you can use." +msgstr "El desenvolupament de l'administrador WinBox es va aturar el 2022 per la manca de mantenidors. Com que ara dirigim els nostres esforços a fer 86Box encara millor, hem pres la decisió de no suportar més el WinBox com a administrador.\n\nNo es proporcionaran més actualitzacions a través del WinBox, i podríeu trobar un comportament incorrecte si continua utilitzant amb versions más noves del 86Box. Qualsevol report de error relacionat amb el comportament del WinBox serà tancat com a invàlid.\n\nAneu a 86box.net per a una llista d'altres administradors que podeu utilitzar." + +msgid "Generate" +msgstr "Genera" + +msgid "Joystick configuration" +msgstr "Configuració del joystick" + +msgid "Device" +msgstr "Dispositiu" + +msgid "%1 (X axis)" +msgstr "%1 (eix X)" + +msgid "%1 (Y axis)" +msgstr "%1 (eix Y)" + +msgid "MCA devices" +msgstr "Dispositius MCA" + +msgid "List of MCA devices:" +msgstr "Llista de dispositius MCA:" + +msgid "&Tablet tool" +msgstr "Eina de &tauleta" + +msgid "About &Qt" +msgstr "Quant al &Qt" + +msgid "&MCA devices…" +msgstr "Dispositius MCA…" + +msgid "Show non-&primary monitors" +msgstr "Mostrar monitors no prim&aris" + +msgid "Open screenshots &folder…" +msgstr "Obre la ca&rpeta de captures…" + +msgid "Appl&y fullscreen stretch mode when maximized" +msgstr "&Utilitza estirament de la pantalla sencera en modalitat maximitzada" + +msgid "&Cursor/Puck" +msgstr "&Cursor/Puck" + +msgid "&Pen" +msgstr "&Llapis" + +msgid "&Host CD/DVD Drive (%1:)" +msgstr "&Unitat de CD/DVD de l'amfitrió (%1:)" + +msgid "&Connected" +msgstr "&Connectat" + +msgid "Clear image &history" +msgstr "Esborra &historial d'imatges" + +msgid "Create…" +msgstr "Crea…" + +msgid "Host CD/DVD Drive (%1)" +msgstr "Unitat de CD/DVD de l'amfitrió (%1)" + +msgid "Unknown Bus" +msgstr "Bus desconegut" + +msgid "Null Driver" +msgstr "Controlador nul" + +msgid "NIC:" +msgstr "NIC:" + +msgid "NIC %1 (%2) %3" +msgstr "NIC %1 (%2) %3" + +msgid "&NIC %1 (%2) %3" +msgstr "&NIC %1 (%2) %3" + +msgid "Render behavior" +msgstr "Comportament del renderitzador" + +msgid "Use target framerate:" +msgstr "Utilitza la següent freqüència de fotogrames:" + +msgid " fps" +msgstr " fps" + +msgid "VSync" +msgstr "VSync" + +msgid "Synchronize with video" +msgstr "Sincronitzar amb els gràfics" + +msgid "Shaders" +msgstr "Shaders" + +msgid "Remove" +msgstr "Esborra" + +msgid "Browse…" +msgstr "Navega…" + +msgid "Couldn't create OpenGL context." +msgstr "Impossible de crear el context OpenGL." + +msgid "Couldn't switch to OpenGL context." +msgstr "Impossible de canviar al context OpenGL." + +msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" +msgstr "Es requereix la versió 3.0 o superior de l'OpenGL. La versió actual és %1.%2" + +msgid "Error initializing OpenGL" +msgstr "Error en inicialitzar l'OpenGL" + +msgid "\nFalling back to software rendering." +msgstr "\nTornant al renderitzat per software." + +msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgstr "

En escollir imatges de mitjans (CD-ROM, disquet, etc.), el quadred de diàleg d'obertura s'iniciarà en el mateix directori que el fitxer de configuració del 86Box. És probable que aquest ajust només farà una diferència en el macOS.

" + +msgid "This machine might have been moved or copied." +msgstr "Aquesta màquina pot haver estat moguda o bé copiada." + +msgid "In order to ensure proper networking functionality, 86Box needs to know if this machine was moved or copied.\n\nSelect \"I Copied It\" if you are not sure." +msgstr "Per garantir la funcionalitat adequada de la xarxa, el 86Box ha de saber si aquesta màquina s'ha mogut o bé copiat.\n\nSi no esteu segurs, escolliu \"La vaig copiar\"." + +msgid "I Moved It" +msgstr "L'he moguda" + +msgid "I Copied It" +msgstr "L'he copiada" + +msgid "86Box Monitor #%1" +msgstr "Monitor del 86Box %1" + +msgid "No MCA devices." +msgstr "Cap dispositiu MCA." + +msgid "MiB" +msgstr "MiB" + +msgid "GiB" +msgstr "GiB" + +msgid "Network Card #1" +msgstr "Targeta de xarxa 1" + +msgid "Network Card #2" +msgstr "Targeta de xarxa 2" + +msgid "Network Card #3" +msgstr "Targeta de xarxa 3" + +msgid "Network Card #4" +msgstr "Targeta de xarxa 4" + +msgid "Mode:" +msgstr "Modalitat:" + +msgid "Interface:" +msgstr "Interfície:" + +msgid "Adapter:" +msgstr "Adaptador:" + +msgid "VDE Socket:" +msgstr "Sòcol VDE:" + +msgid "TAP Bridge Device:" +msgstr "Dispositiu pont TAP:" + +msgid "86Box Unit Tester" +msgstr "Comprovador d'unitats del 86Box" + +msgid "Novell NetWare 2.x Key Card" +msgstr "Targeta de clau per al Novell NetWare 2.x" + +msgid "Serial port passthrough 1" +msgstr "Passatge de port sèrie 1" + +msgid "Serial port passthrough 2" +msgstr "Passatge de port sèrie 2" + +msgid "Serial port passthrough 3" +msgstr "Passatge de port sèrie 3" + +msgid "Serial port passthrough 4" +msgstr "Passatge de port sèrie 4" + +msgid "Renderer &options…" +msgstr "Opc&ions del renderitzador…" + +msgid "PC/XT Keyboard" +msgstr "Teclat PC/XT" + +msgid "AT Keyboard" +msgstr "Teclat AT" + +msgid "AX Keyboard" +msgstr "Teclat AX" + +msgid "PS/2 Keyboard" +msgstr "Teclat PS/2" + +msgid "PS/55 Keyboard" +msgstr "Teclat PS/55" + +msgid "Keys" +msgstr "Tecles" + +msgid "Logitech/Microsoft Bus Mouse" +msgstr "Ratolí de bus Logitech/Microsoft" + +msgid "Microsoft Bus Mouse (InPort)" +msgstr "Ratolí de bus (InPort)" + +msgid "Mouse Systems Serial Mouse" +msgstr "Ratolí sèrie Mouse Systems" + +msgid "Mouse Systems Bus Mouse" +msgstr "Ratolí de bus Mouse Systems" + +msgid "Microsoft Serial Mouse" +msgstr "Ratolí sèrie Microsoft" + +msgid "Microsoft Serial BallPoint" +msgstr "Ratolí sèrie Microsoft BallPoint" + +msgid "Logitech Serial Mouse" +msgstr "Ratolí sèrie Logitech" + +msgid "PS/2 Mouse" +msgstr "Ratolì PS/2" + +msgid "PS/2 QuickPort Mouse" +msgstr "Ratolì PS/2 QuickPort" + +msgid "3M MicroTouch (Serial)" +msgstr "3M MicroTouch (sèrie)" + +msgid "Default Baud rate" +msgstr "Velocitat de transmissió per defecte" + +msgid "Standard Hayes-compliant Modem" +msgstr "Mòdem estàndard compatible amb Hayes" + +msgid "Roland MT-32 Emulation" +msgstr "Emulació Roland MT-32" + +msgid "Roland MT-32 (New) Emulation" +msgstr "Emulació Roland MT-32 (nou)" + +msgid "Roland CM-32L Emulation" +msgstr "Emulació Roland CM-32L" + +msgid "Roland CM-32LN Emulation" +msgstr "Emulació Roland CM-32LN" + +msgid "OPL4-ML Daughterboard" +msgstr "Placa filla OPL4-ML" + +msgid "System MIDI" +msgstr "MIDI del sistema" + +msgid "MIDI Input Device" +msgstr "Dispositiu d'entrada MIDI" + +msgid "BIOS file" +msgstr "Fitxer de la BIOS" + +msgid "BIOS file (ROM #1)" +msgstr "Fitxer de la BIOS (ROM núm. 1)" + +msgid "BIOS file (ROM #2)" +msgstr "Fitxer de la BIOS (ROM núm. 2)" + +msgid "BIOS file (ROM #3)" +msgstr "Fitxer de la BIOS (ROM núm. 3)" + +msgid "BIOS file (ROM #4)" +msgstr "Fitxer de la BIOS (ROM núm. 4)" + +msgid "BIOS address" +msgstr "Adreça de la BIOS" + +msgid "BIOS address (ROM #1)" +msgstr "Adreça de la BIOS (ROM núm. 1)" + +msgid "BIOS address (ROM #2)" +msgstr "Adreça de la BIOS (ROM núm. 2)" + +msgid "BIOS address (ROM #3)" +msgstr "Adreça de la BIOS (ROM núm. 3)" + +msgid "BIOS address (ROM #4)" +msgstr "Adreça de la BIOS (ROM núm. 4)" + +msgid "Enable BIOS extension ROM Writes" +msgstr "Activa l'escriptura per a la ROM d'extensió de la BIOS" + +msgid "Enable BIOS extension ROM Writes (ROM #1)" +msgstr "Activa l'escriptura per a la ROM d'extensió de la BIOS (ROM núm. 1)" + +msgid "Enable BIOS extension ROM Writes (ROM #2)" +msgstr "Activa l'escriptura per a la ROM d'extensió de la BIOS (ROM núm. 2)" + +msgid "Enable BIOS extension ROM Writes (ROM #3)" +msgstr "Activa l'escriptura per a la ROM d'extensió de la BIOS (ROM núm. 3)" + +msgid "Enable BIOS extension ROM Writes (ROM #4)" +msgstr "Activa l'escriptura per a la ROM d'extensió de la BIOS (ROM núm. 4)" + +msgid "Linear framebuffer base" +msgstr "Base del búfer lineal de pantalla" + +msgid "Address" +msgstr "Adreça" + +msgid "IRQ" +msgstr "IRQ" + +msgid "Serial port IRQ" +msgstr "IRQ del port sèrie" + +msgid "Parallel port IRQ" +msgstr "IRQ del port paral·lel" + +msgid "Hard disk" +msgstr "Disc dur" + +msgid "BIOS Revision" +msgstr "Revisió de la BIOS" + +msgid "BIOS Version" +msgstr "Versió de la BIOS" + +msgid "BIOS Language" +msgstr "Idioma de la BIOS" + +msgid "IBM 5161 Expansion Unit" +msgstr "Unitat d'expansió IBM 5161" + +msgid "IBM Cassette Basic" +msgstr "IBM Basic per a cinta" + +msgid "Translate 26 -> 17" +msgstr "Traduir 26 -> 17" + +msgid "Language" +msgstr "Idioma" + +msgid "Enable backlight" +msgstr "Activa retroiŀluminació" + +msgid "Invert colors" +msgstr "Inverteix colors" + +msgid "BIOS size" +msgstr "Mida de la BIOS" + +msgid "BIOS size (ROM #1)" +msgstr "Mida de la BIOS (ROM núm. 1)" + +msgid "BIOS size (ROM #2)" +msgstr "Mida de la BIOS (ROM núm. 2)" + +msgid "BIOS size (ROM #3)" +msgstr "Mida de la BIOS (ROM núm. 3)" + +msgid "BIOS size (ROM #4)" +msgstr "Mida de la BIOS (ROM núm. 4)" + +msgid "Map C0000-C7FFF as UMB" +msgstr "Mapeja C0000-C7FFF com a UMB" + +msgid "Map C8000-CFFFF as UMB" +msgstr "Mapeja C8000-CFFFF com a UMB" + +msgid "Map D0000-D7FFF as UMB" +msgstr "Mapeja D0000-D7FFF com a UMB" + +msgid "Map D8000-DFFFF as UMB" +msgstr "Mapeja D8000-DFFFF com a UMB" + +msgid "Map E0000-E7FFF as UMB" +msgstr "Mapeja E0000-E7FFF com a UMB" + +msgid "Map E8000-EFFFF as UMB" +msgstr "Mapeja E8000-EFFFF com a UMB" + +msgid "JS9 Jumper (JIM)" +msgstr "Jumper JS9 (JIM)" + +msgid "MIDI Output Device" +msgstr "Dispositiu de sortida MIDI" + +msgid "MIDI Real time" +msgstr "MIDI en temps real" + +msgid "MIDI Thru" +msgstr "Passatge de la entrada MIDI" + +msgid "MIDI Clockout" +msgstr "Sortida del rellotge MIDI" + +msgid "Output Gain" +msgstr "Guany de la sortida" + +msgid "Chorus" +msgstr "Cor" + +msgid "Chorus Voices" +msgstr "Veus del cor" + +msgid "Chorus Level" +msgstr "Nivell del cor" + +msgid "Chorus Speed" +msgstr "Velocitat del cor" + +msgid "Chorus Depth" +msgstr "Profunditat del cor" + +msgid "Chorus Waveform" +msgstr "Forma d'ona del cor" + +msgid "Reverb" +msgstr "Reverberació" + +msgid "Reverb Room Size" +msgstr "Mida de l'habitació de reverberació" + +msgid "Reverb Damping" +msgstr "Amortiment de reverberació" + +msgid "Reverb Width" +msgstr "Amplada de reverberació" + +msgid "Reverb Level" +msgstr "Nivell de reverberació" + +msgid "Interpolation Method" +msgstr "Mètode de interpolació" + +msgid "Dynamic Sample Loading" +msgstr "Càrrega dinàmica de mostres" + +msgid "Reverb Output Gain" +msgstr "Guany de sortida de reverberació" + +msgid "Reversed stereo" +msgstr "Estéreo invertit" + +msgid "Nice ramp" +msgstr "Rampa agradable" + +msgid "Hz" +msgstr "Hz" + +msgid "Buttons" +msgstr "Botons" + +msgid "Serial Port" +msgstr "Port sèrie" + +msgid "RTS toggle" +msgstr "Commutació RTS" + +msgid "Revision" +msgstr "Revisió" + +msgid "Controller" +msgstr "Controlador" + +msgid "Show Crosshair" +msgstr "Mostrar mirada creuada" + +msgid "DMA" +msgstr "DMA" + +msgid "MAC Address" +msgstr "Adreça MAC" + +msgid "MAC Address OUI" +msgstr "OUI de la adreça MAC" + +msgid "Enable BIOS" +msgstr "Activar la BIOS" + +msgid "Baud Rate" +msgstr "Velocitat de transmissió" + +msgid "TCP/IP listening port" +msgstr "Port TCP/IP d'escolta" + +msgid "Phonebook File" +msgstr "Fitxer de llista de contactes" + +msgid "Telnet emulation" +msgstr "Emulació Telnet" + +msgid "RAM Address" +msgstr "Adreça del RAM" + +msgid "RAM size" +msgstr "Mida de la RAM" + +msgid "Initial RAM size" +msgstr "Mida inicial de la RAM" + +msgid "Serial Number" +msgstr "Número de sèrie" + +msgid "Host ID" +msgstr "ID de l'amfitrió" + +msgid "FDC Address" +msgstr "Adreça del FDC" + +msgid "MPU-401 Address" +msgstr "Adreça del MPU-401" + +msgid "MPU-401 IRQ" +msgstr "IRQ del MPU-401" + +msgid "Receive MIDI input" +msgstr "Rebre entrada MIDI" + +msgid "Low DMA" +msgstr "DMA baix" + +msgid "Enable Game port" +msgstr "Activa port de joystick" + +msgid "Enable Adlib ports" +msgstr "Activa ports Adlib" + +msgid "SID Model" +msgstr "Model del SID" + +msgid "SID Filter Strength" +msgstr "Força del filtatge del SID" + +msgid "Surround module" +msgstr "Mòdul surround" + +msgid "SB Address" +msgstr "Adreça de la SB" + +msgid "Adlib Address" +msgstr "Adreça de l'Adlib" + +msgid "Use EEPROM setting" +msgstr "Uitilitza la configuració de l'EEPROM" + +msgid "WSS IRQ" +msgstr "IRQ del WSS" + +msgid "WSS DMA" +msgstr "DMA del WSS" + +msgid "RTC IRQ" +msgstr "IRQ RTC" + +msgid "RTC Port Address" +msgstr "Adreça del port RTC" + +msgid "Onboard RTC" +msgstr "RTC integrat" + +msgid "Not installed" +msgstr "No instal·lat" + +msgid "Enable OPL" +msgstr "Activa OPL" + +msgid "Receive MIDI input (MPU-401)" +msgstr "Rebre entrada MIDI (MPU-401)" + +msgid "SB low DMA" +msgstr "DMA baix de la SB" + +msgid "6CH variant (6-channel)" +msgstr "Variant 6CH (6 canals)" + +msgid "Enable CMS" +msgstr "Activar CMS" + +msgid "Mixer" +msgstr "Mesclador" + +msgid "High DMA" +msgstr "DMA alt" + +msgid "Control PC speaker" +msgstr "Controla l'altaveu del PC" + +msgid "Memory size" +msgstr "Mida de memòria" + +msgid "EMU8000 Address" +msgstr "Adreça del EMU8000" + +msgid "IDE Controller" +msgstr "Controladora IDE" + +msgid "Codec" +msgstr "Codec" + +msgid "GUS type" +msgstr "Tipus de GUS" + +msgid "Enable 0x04 \"Exit 86Box\" command" +msgstr "Activa ordre 0x04 \"Surt de 86Box\"" + +msgid "Display type" +msgstr "Tipus de pantalla" + +msgid "Composite type" +msgstr "Tipus de pantalla composta" + +msgid "RGB type" +msgstr "Tipus de pantalla RGB" + +msgid "Line doubling type" +msgstr "Tipus de duplicació de línia" + +msgid "Snow emulation" +msgstr "Emulació de neu" + +msgid "Monitor type" +msgstr "Tipus de monitor" + +msgid "Character set" +msgstr "Conjunt de caràcters" + +msgid "XGA type" +msgstr "Tipus de XGA" + +msgid "Instance" +msgstr "Instància" + +msgid "MMIO Address" +msgstr "Adreça del MMIO" + +msgid "RAMDAC type" +msgstr "Tipus de RAMDAC" + +msgid "Blend" +msgstr "Mescla" + +msgid "Font" +msgstr "Tipus de lletra" + +msgid "Bilinear filtering" +msgstr "Filtració bilineal" + +msgid "Video chroma-keying" +msgstr "Croma-clau de vídeo" + +msgid "Dithering" +msgstr "Díthering" + +msgid "Enable NMI for CGA emulation" +msgstr "Activar NMI per a l'emulació del CGA" + +msgid "Voodoo type" +msgstr "Tipus de Voodoo" + +msgid "Framebuffer memory size" +msgstr "Mida de memòria del búffer de la pantalla" + +msgid "Texture memory size" +msgstr "Mida de memòria de textura" + +msgid "Dither subtraction" +msgstr "Subtracció de dither" + +msgid "Screen Filter" +msgstr "Filtre de pantalla" + +msgid "Render threads" +msgstr "Fils de renderització" + +msgid "SLI" +msgstr "SLI" + +msgid "Start Address" +msgstr "Adreça inicial" + +msgid "Contiguous Size" +msgstr "Mida contígua" + +msgid "I/O Width" +msgstr "Amplada de E/S" + +msgid "Transfer Speed" +msgstr "Velocitat de transferència" + +msgid "EMS mode" +msgstr "Modalitat EMS" + +msgid "EMS Address" +msgstr "Adreça de l'EMS" + +msgid "EMS 1 Address" +msgstr "Adreça de l'EMS 1" + +msgid "EMS 2 Address" +msgstr "Adreça de l'EMS 2" + +msgid "EMS Memory Size" +msgstr "Mida de la memòria EMS" + +msgid "EMS 1 Memory Size" +msgstr "Mida de la memòria EMS 1" + +msgid "EMS 2 Memory Size" +msgstr "Mida de la memòria EMS 2" + +msgid "Enable EMS" +msgstr "Activa EMS" + +msgid "Enable EMS 1" +msgstr "Activa EMS 1" + +msgid "Enable EMS 2" +msgstr "Activa EMS 2" + +msgid "Address for > 2 MB" +msgstr "Adreça per a > 2 MB" + +msgid "Frame Address" +msgstr "Adreça del marc" + +msgid "USA" +msgstr "EUA" + +msgid "Danish" +msgstr "Danés" + +msgid "Always at selected speed" +msgstr "Sempre a la velocitat escollida" + +msgid "BIOS setting + Hotkeys (off during POST)" +msgstr "Configuració de la BIOS + Tecles d'accés ràpid (desactivades durant el POST)" + +msgid "64 KB starting from F0000" +msgstr "64 KB a partir de F0000" + +msgid "128 KB starting from E0000 (address MSB inverted, last 64 KB first)" +msgstr "128 KB a partir d'E0000 (MSB d'adreça invertida, darrers 64 KB primer)" + +msgid "Sine" +msgstr "Sinusoidal" + +msgid "Triangle" +msgstr "Triangular" + +msgid "Linear" +msgstr "Lineal" + +msgid "4th Order" +msgstr "De 4t ordre" + +msgid "7th Order" +msgstr "De 7è ordre" + +msgid "Non-timed (original)" +msgstr "No cronometrat (original)" + +msgid "45 Hz (JMP2 not populated)" +msgstr "45 Hz (JMP2 no poblat)" + +msgid "Two" +msgstr "Dos" + +msgid "Three" +msgstr "Tres" + +msgid "Wheel" +msgstr "Roda" + +msgid "Five + Wheel" +msgstr "Cinc + roda" + +msgid "Five + 2 Wheels" +msgstr "Cinc + 2 rodes" + +msgid "A3 - SMT2 Serial / SMT3(R)V" +msgstr "A3 - SMT2 sèrie / SMT3(R)V" + +msgid "Q1 - SMT3(R) Serial" +msgstr "Q1 - SMT3(R) sèrie" + +msgid "8 KB" +msgstr "8 KB" + +msgid "32 KB" +msgstr "32 KB" + +msgid "16 KB" +msgstr "16 KB" + +msgid "64 KB" +msgstr "64 KB" + +msgid "Disable BIOS" +msgstr "Desactiva la BIOS" + +msgid "512 KB" +msgstr "512 KB" + +msgid "2 MB" +msgstr "2 MB" + +msgid "8 MB" +msgstr "8 MB" + +msgid "28 MB" +msgstr "28 MB" + +msgid "1 MB" +msgstr "1 MB" + +msgid "4 MB" +msgstr "4 MB" + +msgid "12 MB" +msgstr "12 MB" + +msgid "16 MB" +msgstr "16 MB" + +msgid "20 MB" +msgstr "20 MB" + +msgid "24 MB" +msgstr "24 MB" + +msgid "SigmaTel STAC9721T (stereo)" +msgstr "SigmaTel STAC9721T (estéreo)" + +msgid "256 KB" +msgstr "256 KB" + +msgid "Composite" +msgstr "Compost" + +msgid "True color" +msgstr "Color real" + +msgid "Old" +msgstr "Antic" + +msgid "New" +msgstr "Nou" + +msgid "Color (generic)" +msgstr "Color (genèric)" + +msgid "Green Monochrome" +msgstr "Monocromàtic verd" + +msgid "Amber Monochrome" +msgstr "Monocromàtic ambre" + +msgid "Gray Monochrome" +msgstr "Monocromàtic gris" + +msgid "Color (no brown)" +msgstr "Color (sense marró)" + +msgid "Color (IBM 5153)" +msgstr "Color (IBM 5153)" + +msgid "Simple doubling" +msgstr "Duplicació simple" + +msgid "sRGB interpolation" +msgstr "Interpolació sRGB" + +msgid "Linear interpolation" +msgstr "Interpolació lineal" + +msgid "Has secondary 8x8 character set" +msgstr "Té conjunt de caràcters 8x8 secundari" + +msgid "Has Quadcolor II daughter board" +msgstr "Té placa filla Quadcolor II" + +msgid "Alternate monochrome contrast" +msgstr "Contrast monocromátic alternatiu" + +msgid "128 KB" +msgstr "128 KB" + +msgid "Monochrome (5151/MDA) (white)" +msgstr "Monocromàtic (5151/MDA) (blanc)" + +msgid "Monochrome (5151/MDA) (green)" +msgstr "Monocromàtic (5151/MDA) (verd)" + +msgid "Monochrome (5151/MDA) (amber)" +msgstr "Monocromàtic (5151/MDA) (ambre)" + +msgid "Color 40x25 (5153/CGA)" +msgstr "Color 40x25 (5153/CGA)" + +msgid "Color 80x25 (5153/CGA)" +msgstr "Color 80x25 (5153/CGA)" + +msgid "Enhanced Color - Normal Mode (5154/ECD)" +msgstr "Color millorat - modalitat normal (5154/ECD)" + +msgid "Enhanced Color - Enhanced Mode (5154/ECD)" +msgstr "Color millorat - modalitat millorada (5154/ECD)" + +msgid "Green" +msgstr "Verd" + +msgid "Amber" +msgstr "Ambre" + +msgid "Gray" +msgstr "Gris" + +msgid "Grayscale" +msgstr "Escala de grisos" + +msgid "Color" +msgstr "Color" + +msgid "U.S. English" +msgstr "Anglès dels EUA" + +msgid "Scandinavian" +msgstr "Escandinau" + +msgid "Other languages" +msgstr "Altres idiomes" + +msgid "Bochs latest" +msgstr "Bochs més nou" + +msgid "Apply overscan deltas" +msgstr "Aplicar deltes de l'overscan" + +msgid "Mono Interlaced" +msgstr "Monocromàtic entrallaçat" + +msgid "Mono Non-Interlaced" +msgstr "Monocromàtic no entrallaçat" + +msgid "Color Interlaced" +msgstr "Color entrallaçat" + +msgid "Color Non-Interlaced" +msgstr "Color no entrallaçat" + +msgid "3Dfx Voodoo Graphics" +msgstr "Gràfics 3dfx Voodoo" + +msgid "3Dfx Voodoo 2" +msgstr "3Dfx Voodoo 2" + +msgid "Obsidian SB50 + Amethyst (2 TMUs)" +msgstr "Obsidian SB50 + Amethyst (2 unitats TMU)" + +msgid "8-bit" +msgstr "8 bits" + +msgid "16-bit" +msgstr "16 bits" + +msgid "Standard (150ns)" +msgstr "Estàndard (150ns)" + +msgid "High-Speed (120ns)" +msgstr "Alta velocitat (120ns)" + +msgid "Enabled" +msgstr "Activat" + +msgid "Standard" +msgstr "Estàndard" + +msgid "High-Speed" +msgstr "Alta velocitat" + +msgid "Stereo LPT DAC" +msgstr "DAC LPT estèreo" + +msgid "Generic Text Printer" +msgstr "Impressora genèrica de text" + +msgid "Generic ESC/P 2 Dot-Matrix Printer" +msgstr "Impressora genèrica matricial ESC/P 2" + +msgid "Generic PostScript Printer" +msgstr "Impressora genèrica PostScript" + +msgid "Generic PCL5e Printer" +msgstr "Impresora genèrica PCL5e" + +msgid "Parallel Line Internet Protocol" +msgstr "Protocol d'Internet de línia paralela" + +msgid "Protection Dongle for Savage Quest" +msgstr "Dongle de protecció per a Savage Quest" + +msgid "Serial Passthrough Device" +msgstr "Dispositiu de passatge de port sèrie" + +msgid "Passthrough Mode" +msgstr "Modalitat de passatge" + +msgid "Host Serial Device" +msgstr "Dispositiu serie del amfitrió" + +msgid "Name of pipe" +msgstr "Nom de conducta" + +msgid "Data bits" +msgstr "Bits de dades" + +msgid "Stop bits" +msgstr "Bits d'aturada" + +msgid "Baud Rate of Passthrough" +msgstr "Velocitat de transmissió de passatge" + +msgid "Named Pipe (Server)" +msgstr "Conducta anomenada (servidor)" + +msgid "Named Pipe (Client)" +msgstr "Conducta anomenada (client)" + +msgid "Host Serial Passthrough" +msgstr "Passatge del port sèrie de l'amfitrió" + +msgid "E&ject %1" +msgstr "E&xpulsa %1" + +msgid "&Unmute" +msgstr "&Reactiva so" + +msgid "Softfloat FPU" +msgstr "FPU Softfloat" + +msgid "High performance impact" +msgstr "Alt impacte en el rendiment" + +msgid "[Generic] RAM Disk (max. speed)" +msgstr "[Genèric] Disc RAM (velocitat màxima)" + +msgid "[Generic] 1989 (3500 RPM)" +msgstr "[Genèric] 1989 (3500 RPM)" + +msgid "[Generic] 1992 (3600 RPM)" +msgstr "[Genèric] 1992 (3600 RPM)" + +msgid "[Generic] 1994 (4500 RPM)" +msgstr "[Genèric] 1994 (4500 RPM)" + +msgid "[Generic] 1996 (5400 RPM)" +msgstr "[Genèric] 1996 (5400 RPM)" + +msgid "[Generic] 1997 (5400 RPM)" +msgstr "[Genèric] 1997 (5400 RPM)" + +msgid "[Generic] 1998 (5400 RPM)" +msgstr "[Genèric] 1998 (5400 RPM)" + +msgid "[Generic] 2000 (7200 RPM)" +msgstr "[Genèric] 2000 (7200 RPM)" + +msgid "IBM 8514/A clone (ISA)" +msgstr "Clon IBM 8514/A (ISA)" + +msgid "Vendor" +msgstr "Fabricant" + +msgid "30 Hz (JMP2 = 1)" +msgstr "30 Hz (JMP2 = 1)" + +msgid "60 Hz (JMP2 = 2)" +msgstr "60 Hz (JMP2 = 2)" + +msgid "Generic PC/XT Memory Expansion" +msgstr "Expansió genèrica PC/XT de memòria" + +msgid "Generic PC/AT Memory Expansion" +msgstr "Expansió genèrica PC/AT de memòria" + +msgid "Unable to find Dot-Matrix fonts" +msgstr "No fou possible trobar els tipus de lletra matricials" + +msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P 2 Dot-Matrix Printer." +msgstr "Els tipus de lletra TrueType en el directori \"roms/printer/fonts\" són imprescindibles per l'emulació de la impressora genèrica matricial ESC/P 2." + +msgid "Inhibit multimedia keys" +msgstr "Inhibir tecles multimèdia" + +msgid "Ask for confirmation before saving settings" +msgstr "Demana confirmació abans de desar la configuració" + +msgid "Ask for confirmation before hard resetting" +msgstr "Demana confirmació abans de la reiniciació completa" + +msgid "Ask for confirmation before quitting" +msgstr "Demana confirmació abans de sortir" + +msgid "Options" +msgstr "Opcions" + +msgid "Model" +msgstr "Model" + +msgid "Model:" +msgstr "Model:" + +msgid "Failed to initialize Vulkan renderer." +msgstr "Error en inicialitzar el renderitzador Vulkan." + +msgid "GLSL Error" +msgstr "Error de GLSL" + +msgid "Could not load shader: %1" +msgstr "No fou possible carregar el shader: %1" + +msgid "Could not load texture: %1" +msgstr "Error en carregar la textura: %1" + +msgid "Could not compile shader:\n\n%1" +msgstr "Error en compilar el shader:\n\n%1" + +msgid "Program not linked:\n\n%1" +msgstr "Programa no vinculat:\n\n%1" + +msgid "Shader Manager" +msgstr "Administrador de shaders" + +msgid "Shader Configuration" +msgstr "Configuració de shaders" + +msgid "Add" +msgstr "Afegeix" + +msgid "Move up" +msgstr "Moure cap amunt" + +msgid "Move down" +msgstr "Moure cap avall" + +msgid "Could not load file %1" +msgstr "Error en carregar el fitxer %1" + +msgid "Key Bindings:" +msgstr "Dreceres de teclat:" + +msgid "Action" +msgstr "Acció" + +msgid "Keybind" +msgstr "Drecera" + +msgid "Clear binding" +msgstr "Esborra drecera" + +msgid "Bind" +msgstr "Vincula" + +msgid "Bind Key" +msgstr "Vincula tecla" + +msgid "Enter key combo:" +msgstr "Escriviu combinació de tecles:" + +msgid "Bind conflict" +msgstr "Conflicte entre dreceres" + +msgid "This key combo is already in use." +msgstr "Aquesta combinació de tecles ja està en ús." + +msgid "Send Control+Alt+Del" +msgstr "Envia Control+Alt+Supr" + +msgid "Send Control+Alt+Escape" +msgstr "Envia Control+Alt+Esc" + +msgid "Toggle fullscreen" +msgstr "Alternar pantalla completa" + +msgid "Toggle UI in fullscreen" +msgstr "Alternar interfície d'usuari en modalitat de pantalla completa" + +msgid "Release mouse pointer" +msgstr "Allibera el punter del ratolí" + +msgid "Toggle pause" +msgstr "Alterna pausa" + +msgid "Toggle mute" +msgstr "Alterna silenci" + +msgid "Text files" +msgstr "Fitxers de text" + +msgid "ROM files" +msgstr "Fitxers de ROM" + +msgid "SoundFont files" +msgstr "Fitxers SoundFont" + +msgid "Local Switch" +msgstr "Commutador local" + +msgid "Remote Switch" +msgstr "Commutador remot" + +msgid "Switch:" +msgstr "Commutador:" + +msgid "Hub Mode" +msgstr "Modalitat de concentrador" + +msgid "Hostname:" +msgstr "Nom de l'amfitrió:" + +msgid "ISA RAM:" +msgstr "RAM ISA:" + +msgid "ISA ROM:" +msgstr "ROM ISA:" + +msgid "&Wipe NVRAM" +msgstr "&Esborra la NVRAM" + +msgid "This will delete all NVRAM (and related) files of the virtual machine located in the \"nvr\" subdirectory. You'll have to reconfigure the BIOS (and possibly other devices inside the VM) settings again if applicable.\n\nAre you sure you want to wipe all NVRAM contents of the virtual machine \"%1\"?" +msgstr "Això suprimirà tots els fitxers NVRAM (i relacionats) de la màquina virtual situats al subdirectori \"nvr\". Haureu de tornar a reconfigurar la configuració de la BIOS (i potser d'altres dispositius a l'interior de la MV) si s'escau.\n\nEsteu segurs que voleu esborrar tot el contingut de la NVRAM de la màquina virtual \"%1\"?" + +msgid "Success" +msgstr "Èxit" + +msgid "Successfully wiped the NVRAM contents of the virtual machine \"%1\"" +msgstr "El contingut de la NVRAM de la màquina virtual \"%1\" s'ha esborrat amb èxit" + +msgid "An error occurred trying to wipe the NVRAM contents of the virtual machine \"%1\"" +msgstr "S'ha produït un error en intentar esborrar el contingut de la NVRAM de la màquina virtual \"%1\"" + +msgid "%1 VM Manager" +msgstr "Administrador de MV de %1" + +msgid "%n disk(s)" +msgstr "%n disc(s)" + +msgid "Unknown Status" +msgstr "Estat desconegut" + +msgid "No Machines Found!" +msgstr "No s'han trobat màquines!" + +msgid "Check for updates on startup" +msgstr "Comprova actualitzacions en iniciar" + +msgid "Unable to determine release information" +msgstr "No fou possible determinar la informació de la versió" + +msgid "There was an error checking for updates:\n\n%1\n\nPlease try again later." +msgstr "S'ha produït un error en verificar actualitzacions:\n\n%1\n\nSi us plau, torneu a intentar-ho més tard." + +msgid "Update check complete" +msgstr "Verificació de actualitzacions finalitzada" + +msgid "stable" +msgstr "estable" + +msgid "beta" +msgstr "beta" + +msgid "You are running the latest %1 version of 86Box: %2" +msgstr "Esteu executant l'última versió %1 del 86Box: %2" + +msgid "version" +msgstr "versió" + +msgid "build" +msgstr "compilació" + +msgid "You are currently running version %1." +msgstr "Actualment esteu executant la versió %1." + +msgid "Version %1 is now available." +msgstr "La versió %1 ja és disponible." + +msgid "You are currently running build %1." +msgstr "Actualment esteu executant la compialació %1." + +msgid "Build %1 is now available." +msgstr "La compilació %1 ja és disponible." + +msgid "Would you like to visit the download page?" +msgstr "Voleu visitar la pàgina de descàrregues?" + +msgid "Visit download page" +msgstr "Visita la pàgina de descàrregues" + +msgid "Update check" +msgstr "Verificació de actualitzacions" + +msgid "Checking for updates…" +msgstr "Verificant las actualitzacions…" + +msgid "86Box Update" +msgstr "Actualització del 86Box" + +msgid "Release notes:" +msgstr "Notes de versió:" + +msgid "%1 Hz" +msgstr "%1 Hz" + +msgid "Virtual machine crash" +msgstr "Finalització inesperada de la màquina virtual" + +msgid "The virtual machine \"%1\"'s process has unexpectedly terminated with exit code %2." +msgstr "El procés de la màquina virtual \"%1\" s'ha finalitzat inesperadament amb con el codi de sortida %2." + +msgid "The system will not be added." +msgstr "El sistema no serà afegit." + +msgid "&Update mouse every CPU frame" +msgstr "&Actualitza l'estat del ratolí a cada bloc del CPU" + +msgid "Hue" +msgstr "Matís" + +msgid "Saturation" +msgstr "Saturació" + +msgid "Contrast" +msgstr "Contrast" + +msgid "Brightness" +msgstr "Luminositat" + +msgid "Sharpness" +msgstr "Nitidesa" + +msgid "&CGA composite settings…" +msgstr "Configuració de la modalitat compòsita &CGA…" + +msgid "CGA composite settings" +msgstr "Configuració de la modalitat compòsita CGA" + +msgid "Monitor EDID" +msgstr "EDID del monitor" + +msgid "Export…" +msgstr "Exporta…" + +msgid "Export EDID" +msgstr "Exporta l'EDID" + +msgid "EDID file \"%ls\" is too large." +msgstr "El fitxer EDID \"%ls\" és massa gran." + +msgid "OpenGL input scale" +msgstr "Escala de entrada de l'OpenGL" + +msgid "OpenGL input stretch mode" +msgstr "Modalitat de estirament de entrada de l'OpenGL" + +msgid "Color scheme" +msgstr "Esquema de colors" + +msgid "Light" +msgstr "Clar" + +msgid "Dark" +msgstr "Fosc" + +msgid "Search:" +msgstr "Cerca:" + +msgid "Force interpretation" +msgstr "Força interpretació" + +msgid "Allow recompilation" +msgstr "Permetre recompilació" + +msgid "&Force interpretation" +msgstr "&Força interpretació" + +msgid "&Allow recompilation" +msgstr "&Permetre recompilació" + +msgid "&Fast forward" +msgstr "" + +msgid "Fast forward" +msgstr "" + +msgid "To change the system directory, stop all running machines." +msgstr "" diff --git a/src/qt/languages/cs-CZ.po b/src/qt/languages/cs-CZ.po index 5611694c728..bed51f2610a 100644 --- a/src/qt/languages/cs-CZ.po +++ b/src/qt/languages/cs-CZ.po @@ -1,8 +1,14 @@ msgid "" msgstr "" +"PO-Revision-Date: 2026-01-02 21:56+0000\n" +"Last-Translator: David Hrdlička \n" +"Language-Team: Czech \n" +"Language: cs-CZ\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" +"X-Generator: Weblate 5.12.2\n" "X-Language: cs_CZ\n" "X-Source-Language: en_US\n" @@ -66,8 +72,8 @@ msgstr "Open&GL (3.0 Core)" msgid "&VNC" msgstr "&VNC" -msgid "Specify &dimensions..." -msgstr "&Zadat velikost..." +msgid "Specify &dimensions…" +msgstr "&Zadat velikost…" msgid "Force &4:3 display ratio" msgstr "Dodržovat poměr stran &4:3" @@ -192,11 +198,11 @@ msgstr "&Média" msgid "&Tools" msgstr "&Nástroje" -msgid "&Settings..." -msgstr "&Nastavení..." +msgid "&Settings…" +msgstr "&Nastavení…" -msgid "Settings..." -msgstr "Nastavení..." +msgid "Settings…" +msgstr "Nastavení…" msgid "&Update status bar icons" msgstr "&Aktualizovat ikony stavového řádku" @@ -204,17 +210,38 @@ msgstr "&Aktualizovat ikony stavového řádku" msgid "Take s&creenshot" msgstr "Pořídit &screenshot" +msgid "Take screenshot" +msgstr "Pořídit screenshot" + +msgid "Take &raw screenshot" +msgstr "Pořídit n&ezpracovaný screenshot" + +msgid "Take raw screenshot" +msgstr "Pořídit nezpracovaný screenshot" + +msgid "C&opy screenshot" +msgstr "&Zkopírovat screenshot" + +msgid "Copy screenshot" +msgstr "Zkopírovat screenshot" + +msgid "Copy r&aw screenshot" +msgstr "Zkopírovat nez&pracovaný screenshot" + +msgid "Copy raw screenshot" +msgstr "Zkopírovat nezpracovaný screenshot" + msgid "S&ound" msgstr "&Zvuk" -msgid "&Preferences..." -msgstr "&Předvolby..." +msgid "&Preferences…" +msgstr "&Předvolby…" msgid "Enable &Discord integration" msgstr "Povolit integraci s &Discordem" -msgid "Sound &gain..." -msgstr "&Zesílení zvuku..." +msgid "Sound &gain…" +msgstr "&Zesílení zvuku…" msgid "Begin trace" msgstr "Začít trace" @@ -225,20 +252,20 @@ msgstr "Zastavit trace" msgid "&Help" msgstr "Ná&pověda" -msgid "&Documentation..." -msgstr "&Dokumentace..." +msgid "&Documentation…" +msgstr "&Dokumentace…" -msgid "&About 86Box..." -msgstr "&O programu 86Box..." +msgid "&About 86Box…" +msgstr "&O programu 86Box…" -msgid "&New image..." -msgstr "&Nový obraz..." +msgid "&New image…" +msgstr "&Nový obraz…" -msgid "&Existing image..." -msgstr "&Existující obraz..." +msgid "&Existing image…" +msgstr "&Existující obraz…" -msgid "Existing image (&Write-protected)..." -msgstr "Existující obraz (&ochrana proti zápisu)..." +msgid "Existing image (&Write-protected)…" +msgstr "Existující obraz (&ochrana proti zápisu)…" msgid "&Record" msgstr "&Nahrávat" @@ -255,11 +282,11 @@ msgstr "Přetočit na &konec" msgid "E&ject" msgstr "&Vyjmout" -msgid "&Image..." -msgstr "&Obraz..." +msgid "&Image…" +msgstr "&Obraz…" -msgid "E&xport to 86F..." -msgstr "E&xportovat do 86F..." +msgid "E&xport to 86F…" +msgstr "E&xportovat do 86F…" msgid "&Mute" msgstr "&Ztišit" @@ -270,8 +297,8 @@ msgstr "&Vyjmout" msgid "Reload previous image" msgstr "Načíst znova předchozí obraz" -msgid "&Folder..." -msgstr "&Složka..." +msgid "&Folder…" +msgstr "&Složka…" msgid "Preferences" msgstr "Předvolby" @@ -417,17 +444,17 @@ msgstr "Joystick:" msgid "Joystick" msgstr "Joystick" -msgid "Joystick 1..." -msgstr "Joystick 1..." +msgid "Joystick 1…" +msgstr "Joystick 1…" -msgid "Joystick 2..." -msgstr "Joystick 2..." +msgid "Joystick 2…" +msgstr "Joystick 2…" -msgid "Joystick 3..." -msgstr "Joystick 3..." +msgid "Joystick 3…" +msgstr "Joystick 3…" -msgid "Joystick 4..." -msgstr "Joystick 4..." +msgid "Joystick 4…" +msgstr "Joystick 4…" msgid "Sound card #1:" msgstr "Zvuková karta 1:" @@ -516,10 +543,10 @@ msgstr "Povolit port LPT3" msgid "Parallel port 4" msgstr "Povolit port LPT4" -msgid "FD Controller:" +msgid "Floppy disk controller:" msgstr "Disketový řadič:" -msgid "CD-ROM Controller:" +msgid "CD-ROM controller:" msgstr "Řadič CD-ROM:" msgid "Tertiary IDE Controller" @@ -528,11 +555,11 @@ msgstr "Třetí řadič IDE" msgid "Quaternary IDE Controller" msgstr "Čtvrtý řadič IDE" -msgid "Hard disk" -msgstr "Pevný disk" +msgid "Hard disk controllers" +msgstr "Řadiče pevných disků" -msgid "SCSI" -msgstr "SCSI" +msgid "SCSI controllers" +msgstr "Řadiče SCSI" msgid "Controller 1:" msgstr "Řadič 1:" @@ -555,11 +582,11 @@ msgstr "Pevné disky:" msgid "Firmware Version" msgstr "Verze firmware" -msgid "&New..." -msgstr "&Nový..." +msgid "&New…" +msgstr "&Nový…" -msgid "&Existing..." -msgstr "&Existující..." +msgid "&Existing…" +msgstr "&Existující…" msgid "&Remove" msgstr "&Odebrat" @@ -867,9 +894,6 @@ msgstr "Ovladač se 4 tlačítky" msgid "6-button gamepad" msgstr "Ovladač se 6 tlačítky" -msgid "Gravis PC GamePad" -msgstr "Gravis PC GamePad" - msgid "2-button flight yoke" msgstr "Letecký knipl s 2 tlačítky" @@ -897,51 +921,6 @@ msgstr "Volant (3 osy, 3 tlačítka)" msgid "Steering wheel (3-axis, 4-button)" msgstr "Volant (3 osy, 4 tlačítka)" -msgid "CH Flightstick" -msgstr "CH Flightstick" - -msgid "CH Flightstick + CH Pedals" -msgstr "CH Flightstick + CH Pedals" - -msgid "CH Flightstick + CH Pedals Pro" -msgstr "CH Flightstick + CH Pedals Pro" - -msgid "CH Flightstick Pro" -msgstr "CH Flightstick Pro" - -msgid "CH Flightstick Pro + CH Pedals" -msgstr "CH Flightstick Pro + CH Pedals" - -msgid "CH Flightstick Pro + CH Pedals Pro" -msgstr "CH Flightstick Pro + CH Pedals Pro" - -msgid "CH Virtual Pilot" -msgstr "CH Virtual Pilot" - -msgid "CH Virtual Pilot + CH Pedals" -msgstr "CH Virtual Pilot + CH Pedals" - -msgid "CH Virtual Pilot + CH Pedals Pro" -msgstr "CH Virtual Pilot + CH Pedals Pro" - -msgid "CH Virtual Pilot Pro" -msgstr "CH Virtual Pilot Pro" - -msgid "CH Virtual Pilot Pro + CH Pedals" -msgstr "CH Virtual Pilot Pro + CH Pedals" - -msgid "CH Virtual Pilot Pro + CH Pedals Pro" -msgstr "CH Virtual Pilot Pro + CH Pedals Pro" - -msgid "Microsoft SideWinder Pad" -msgstr "Microsoft SideWinder Pad" - -msgid "Thrustmaster Flight Control System" -msgstr "Thrustmaster Flight Control System" - -msgid "Thrustmaster FCS + Rudder Control System" -msgstr "Thrustmaster FCS + Rudder Control System" - msgid "Thrustmaster Formula T1/T2 with adapter" msgstr "Thrustmaster Formula T1/T2 s adaptérem" @@ -996,11 +975,17 @@ msgstr "Vestavěné zařízení" msgid "&File" msgstr "&Soubor" -msgid "&New machine..." -msgstr "&Nový počítač..." +msgid "&New machine…" +msgstr "&Nový počítač…" -msgid "&Check for updates..." -msgstr "&Zkontrolovat aktualizace..." +msgid "New machine…" +msgstr "Nový počítač…" + +msgid "New machine" +msgstr "Nový počítač" + +msgid "&Check for updates…" +msgstr "&Zkontrolovat aktualizace…" msgid "Exit" msgstr "Ukončit" @@ -1170,8 +1155,8 @@ msgstr "Nebylo možné otevřít vybraný konfigurační soubor pro čtení: %1" msgid "Use regular expressions in search box" msgstr "Použít ve vyhledávacím poli regulární výrazy" -msgid "%1 machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" -msgstr "%1 počítač(ů) je stále aktivních. Opravdu chcete ukončit správce virtuálních počítačů?" +msgid "%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" +msgstr "%n počítač(ů) je stále aktivních. Opravdu chcete ukončit správce virtuálních počítačů?" msgid "Add new system wizard" msgstr "Průvodce přidáním nového systému" @@ -1251,26 +1236,23 @@ msgstr "Nastavit zobrazované jméno" msgid "Enter the new display name (blank to reset)" msgstr "Zadejte nové zobrazované jméno (prázdné pole pro vymazání)" -msgid "Change &display name..." -msgstr "Změnit &zobrazované jméno..." - -msgid "Context Menu" -msgstr "Kontextová nabídka" +msgid "Change &display name…" +msgstr "Změnit &zobrazované jméno…" -msgid "&Open folder..." -msgstr "&Otevřít složku..." +msgid "&Open folder…" +msgstr "&Otevřít složku…" -msgid "Open p&rinter tray..." -msgstr "Otevřít zásobník &tiskárny..." +msgid "Open p&rinter tray…" +msgstr "Otevřít zásobník &tiskárny…" -msgid "Set &icon..." -msgstr "Nastavit &ikonu..." +msgid "Set &icon…" +msgstr "Nastavit &ikonu…" msgid "Select an icon" msgstr "Vyberte ikonu" -msgid "C&lone..." -msgstr "K&lonovat..." +msgid "C&lone…" +msgstr "K&lonovat…" msgid "Virtual machine \"%1\" (%2) will be cloned into:" msgstr "Virtuální počítač \"%1\" (%2) bude naklonován do:" @@ -1356,8 +1338,8 @@ msgstr "Žádný snímek obrazovky" msgid "Search" msgstr "Hledat" -msgid "Searching for VMs..." -msgstr "Hledání virtuálních počítačů..." +msgid "Searching for VMs…" +msgstr "Hledání virtuálních počítačů…" msgid "Found %1" msgstr "Nalezeno %1" @@ -1392,11 +1374,11 @@ msgstr "Pevný disk (%1)" msgid "MFM/RLL or ESDI CD-ROM drives never existed" msgstr "CD-ROM mechaniky pro rozhraní MFM/RLL nebo ESDI nikdy neexistovaly" -msgid "Custom..." -msgstr "Vlastní..." +msgid "Custom…" +msgstr "Vlastní…" -msgid "Custom (large)..." -msgstr "Vlastní (velký)..." +msgid "Custom (large)…" +msgstr "Vlastní (velký)…" msgid "Add New Hard Disk" msgstr "Přidat nový pevný disk" @@ -1515,21 +1497,6 @@ msgstr "Časová razítka nadřazeného a podřazeného disku nesouhlasí" msgid "Could not fix VHD timestamp." msgstr "Nebylo možné opravit časové razítko VHD disku." -msgid "MFM/RLL" -msgstr "MFM/RLL" - -msgid "XTA" -msgstr "XTA" - -msgid "ESDI" -msgstr "ESDI" - -msgid "IDE" -msgstr "IDE" - -msgid "ATAPI" -msgstr "ATAPI" - msgid "CD-ROM %1 (%2): %3" msgstr "CD-ROM %1 (%2): %3" @@ -1680,14 +1647,14 @@ msgstr "Nástroj pro tablety" msgid "About &Qt" msgstr "O platformě &Qt" -msgid "&MCA devices..." -msgstr "Zařízení MCA ..." +msgid "&MCA devices…" +msgstr "Zařízení MCA…" msgid "Show non-&primary monitors" msgstr "Zobrazit neprimární monitory" -msgid "Open screenshots &folder..." -msgstr "Otevřít složku se snímky obrazovky..." +msgid "Open screenshots &folder…" +msgstr "Otevřít složku se snímky obrazovky…" msgid "Appl&y fullscreen stretch mode when maximized" msgstr "Použít režim roztá&hnutí při celé obrazovce pro maximalizované okno" @@ -1707,8 +1674,8 @@ msgstr "&Připojeno" msgid "Clear image &history" msgstr "Vymaž &historie snímků" -msgid "Create..." -msgstr "Vytvořit..." +msgid "Create…" +msgstr "Vytvořit…" msgid "Host CD/DVD Drive (%1)" msgstr "Jednotka CD/DVD hostitele (%1)" @@ -1749,8 +1716,8 @@ msgstr "Shadery" msgid "Remove" msgstr "Odstranit" -msgid "Browse..." -msgstr "Procházet..." +msgid "Browse…" +msgstr "Procházet…" msgid "Couldn't create OpenGL context." msgstr "Nepodařilo se vytvořit kontext OpenGL." @@ -1839,8 +1806,8 @@ msgstr "Průchod sériového portu 3" msgid "Serial port passthrough 4" msgstr "Průchod sériového portu 4" -msgid "Renderer &options..." -msgstr "Možnosti rendereru..." +msgid "Renderer &options…" +msgstr "Možnosti rendereru…" msgid "PC/XT Keyboard" msgstr "PC/XT klávesnice" @@ -1893,8 +1860,8 @@ msgstr "3M MicroTouch (sériová)" msgid "Default Baud rate" msgstr "Výchozí přenosová rychlost" -msgid "[COM] Standard Hayes-compliant Modem" -msgstr "[COM] Modem kompatibilní se standardem Hayes" +msgid "Standard Hayes-compliant Modem" +msgstr "Modem kompatibilní se standardem Hayes" msgid "Roland MT-32 Emulation" msgstr "Emulace Roland MT-32" @@ -1936,13 +1903,13 @@ msgid "BIOS address" msgstr "Adresa BIOS" msgid "BIOS address (ROM #1)" -msgstr "Adresa BIOS (ROM 4)" +msgstr "Adresa BIOS (ROM 1)" msgid "BIOS address (ROM #2)" -msgstr "Adresa BIOS (ROM 4)" +msgstr "Adresa BIOS (ROM 2)" msgid "BIOS address (ROM #3)" -msgstr "Adresa BIOS (ROM 4)" +msgstr "Adresa BIOS (ROM 3)" msgid "BIOS address (ROM #4)" msgstr "Adresa BIOS (ROM 4)" @@ -1977,6 +1944,9 @@ msgstr "Přerušení sériového portu" msgid "Parallel port IRQ" msgstr "Přerušení paralelního portu" +msgid "Hard disk" +msgstr "Pevný disk" + msgid "BIOS Revision" msgstr "Revize BIOS" @@ -2052,9 +2022,6 @@ msgstr "Průchod vstupu MIDI" msgid "MIDI Clockout" msgstr "Výstup MIDI hodin" -msgid "SoundFont" -msgstr "SoundFont" - msgid "Output Gain" msgstr "Zesílení výstupu" @@ -2212,16 +2179,16 @@ msgid "WSS DMA" msgstr "DMA kanál WSS" msgid "RTC IRQ" -msgstr "" +msgstr "IRQ hodin reálného času" msgid "RTC Port Address" -msgstr "" +msgstr "Adresa portu hodin reálného času" msgid "Onboard RTC" -msgstr "" +msgstr "Integrované hodiny reálného času" msgid "Not installed" -msgstr "" +msgstr "Nenainstalováno" msgid "Enable OPL" msgstr "Povolit OPL" @@ -2539,7 +2506,7 @@ msgid "Has secondary 8x8 character set" msgstr "Má druhou sadu 8x8 znaků" msgid "Has Quadcolor II daughter board" -msgstr "Má dceřinnou desků Quadcolor II" +msgstr "Má dceřinnou desku Quadcolor II" msgid "Alternate monochrome contrast" msgstr "Alternativní monochromatický kontrast" @@ -2845,10 +2812,7 @@ msgid "Toggle fullscreen" msgstr "Přepnout režim celé obrazovky" msgid "Toggle UI in fullscreen" -msgstr "" - -msgid "Screenshot" -msgstr "Pořídit snímek obrazovky" +msgstr "Přepnout rozhraní při celé obrazovce" msgid "Release mouse pointer" msgstr "Uvolnit kurzor myši" @@ -2964,8 +2928,8 @@ msgstr "Navštívit stránku pro stažení" msgid "Update check" msgstr "Kontrola aktualizací" -msgid "Checking for updates..." -msgstr "Probíhá kontrola aktualizací..." +msgid "Checking for updates…" +msgstr "Probíhá kontrola aktualizací…" msgid "86Box Update" msgstr "Aktualizace 86Box" @@ -3003,8 +2967,8 @@ msgstr "Jas" msgid "Sharpness" msgstr "Ostrost" -msgid "&CGA composite settings..." -msgstr "Nastavení kompozitního výstupu &CGA..." +msgid "&CGA composite settings…" +msgstr "Nastavení kompozitního výstupu &CGA…" msgid "CGA composite settings" msgstr "Nastavení kompozitního výstupu CGA" @@ -3012,8 +2976,8 @@ msgstr "Nastavení kompozitního výstupu CGA" msgid "Monitor EDID" msgstr "EDID monitoru" -msgid "Export..." -msgstr "Exportovat..." +msgid "Export…" +msgstr "Exportovat…" msgid "Export EDID" msgstr "Exportovat EDID" @@ -3038,3 +3002,24 @@ msgstr "Tmavé" msgid "Search:" msgstr "Hledat:" + +msgid "Force interpretation" +msgstr "Vynutit interpretaci" + +msgid "Allow recompilation" +msgstr "Povolit rekompilaci" + +msgid "&Force interpretation" +msgstr "&Vynutit interpretaci" + +msgid "&Allow recompilation" +msgstr "&Povolit rekompilaci" + +msgid "&Fast forward" +msgstr "" + +msgid "Fast forward" +msgstr "" + +msgid "To change the system directory, stop all running machines." +msgstr "" diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po index 3e23d868263..38e82986177 100644 --- a/src/qt/languages/de-DE.po +++ b/src/qt/languages/de-DE.po @@ -72,8 +72,8 @@ msgstr "Open&GL (3.0 Core)" msgid "&VNC" msgstr "&VNC" -msgid "Specify &dimensions..." -msgstr "Fenstergröße &einstellen..." +msgid "Specify &dimensions…" +msgstr "Fenstergröße &einstellen…" msgid "Force &4:3 display ratio" msgstr "&4:3-Seitenverhältnis erzwingen" @@ -198,11 +198,11 @@ msgstr "&Medien" msgid "&Tools" msgstr "&Werkzeuge" -msgid "&Settings..." -msgstr "&Optionen..." +msgid "&Settings…" +msgstr "&Einstellungen…" -msgid "Settings..." -msgstr "Einstellungen..." +msgid "Settings…" +msgstr "Einstellungen…" msgid "&Update status bar icons" msgstr "&Statusleistenicons aktualisieren" @@ -210,17 +210,38 @@ msgstr "&Statusleistenicons aktualisieren" msgid "Take s&creenshot" msgstr "S&creenshot aufnehmen" +msgid "Take screenshot" +msgstr "Screenshot aufnehmen" + +msgid "Take &raw screenshot" +msgstr "&Roh-Screenshot aufnehmen" + +msgid "Take raw screenshot" +msgstr "Roh-Screenshot aufnehmen" + +msgid "C&opy screenshot" +msgstr "Screenshot k&opieren" + +msgid "Copy screenshot" +msgstr "Screenshot kopieren" + +msgid "Copy r&aw screenshot" +msgstr "R&oh-Screenshot kopieren" + +msgid "Copy raw screenshot" +msgstr "Roh-Screenshot kopieren" + msgid "S&ound" msgstr "&Ton" -msgid "&Preferences..." -msgstr "&Einstellungen..." +msgid "&Preferences…" +msgstr "&Preferenzen…" msgid "Enable &Discord integration" msgstr "&Discord-Integration einschalten" -msgid "Sound &gain..." -msgstr "&Klangverstärkung..." +msgid "Sound &gain…" +msgstr "&Klangverstärkung…" msgid "Begin trace" msgstr "Tracing starten" @@ -231,20 +252,20 @@ msgstr "Tracing beenden" msgid "&Help" msgstr "&Hilfe" -msgid "&Documentation..." -msgstr "&Dokumentation..." +msgid "&Documentation…" +msgstr "&Dokumentation…" -msgid "&About 86Box..." -msgstr "&Über 86Box..." +msgid "&About 86Box…" +msgstr "&Über 86Box…" -msgid "&New image..." -msgstr "&Neues Abbild..." +msgid "&New image…" +msgstr "&Neues Abbild…" -msgid "&Existing image..." -msgstr "&Bestehendes Abbild..." +msgid "&Existing image…" +msgstr "&Bestehendes Abbild…" -msgid "Existing image (&Write-protected)..." -msgstr "Bestehendes Abbild (&schreibgeschützt)..." +msgid "Existing image (&Write-protected)…" +msgstr "Bestehendes Abbild (&schreibgeschützt)…" msgid "&Record" msgstr "&Aufnehmen" @@ -261,11 +282,11 @@ msgstr "&An das Ende vorspulen" msgid "E&ject" msgstr "A&uswerfen" -msgid "&Image..." -msgstr "&Abbild..." +msgid "&Image…" +msgstr "&Abbild…" -msgid "E&xport to 86F..." -msgstr "&In das 86F-Format e&xportieren..." +msgid "E&xport to 86F…" +msgstr "&In das 86F-Format e&xportieren…" msgid "&Mute" msgstr "&Stummschalten" @@ -276,11 +297,11 @@ msgstr "L&eer" msgid "Reload previous image" msgstr "Voriges Abbild neu laden" -msgid "&Folder..." -msgstr "&Verzeichnis..." +msgid "&Folder…" +msgstr "&Verzeichnis…" msgid "Preferences" -msgstr "Einstellungen" +msgstr "Preferenzen" msgid "Sound Gain" msgstr "Klangverstärkung" @@ -289,7 +310,7 @@ msgid "New Image" msgstr "Neues Abbild" msgid "Settings" -msgstr "Optionen" +msgstr "Einstellungen" msgid "Specify Main Window Dimensions" msgstr "Fenstergröße einstellen" @@ -423,17 +444,17 @@ msgstr "Joystick:" msgid "Joystick" msgstr "Joystick" -msgid "Joystick 1..." -msgstr "Joystick 1..." +msgid "Joystick 1…" +msgstr "Joystick 1…" -msgid "Joystick 2..." -msgstr "Joystick 2..." +msgid "Joystick 2…" +msgstr "Joystick 2…" -msgid "Joystick 3..." -msgstr "Joystick 3..." +msgid "Joystick 3…" +msgstr "Joystick 3…" -msgid "Joystick 4..." -msgstr "Joystick 4..." +msgid "Joystick 4…" +msgstr "Joystick 4…" msgid "Sound card #1:" msgstr "Soundkarte 1:" @@ -522,10 +543,10 @@ msgstr "Parallelport 3" msgid "Parallel port 4" msgstr "Parallelport 4" -msgid "FD Controller:" +msgid "Floppy disk controller:" msgstr "Disketten-Controller:" -msgid "CD-ROM Controller:" +msgid "CD-ROM controller:" msgstr "CD-ROM-Controller:" msgid "Tertiary IDE Controller" @@ -534,11 +555,11 @@ msgstr "Tertiärer IDE-Controller" msgid "Quaternary IDE Controller" msgstr "Quartärer IDE-Controller" -msgid "Hard disk" -msgstr "Festplatte" +msgid "Hard disk controllers" +msgstr "Festplattencontroller" -msgid "SCSI" -msgstr "SCSI" +msgid "SCSI controllers" +msgstr "SCSI-Controller" msgid "Controller 1:" msgstr "Controller 1:" @@ -561,11 +582,11 @@ msgstr "Festplatten:" msgid "Firmware Version" msgstr "Firmware-Version" -msgid "&New..." -msgstr "&Neu..." +msgid "&New…" +msgstr "&Neu…" -msgid "&Existing..." -msgstr "&Vorhanden..." +msgid "&Existing…" +msgstr "&Vorhanden…" msgid "&Remove" msgstr "&Entfernen" @@ -873,9 +894,6 @@ msgstr "4-Tasten-Gamepad" msgid "6-button gamepad" msgstr "6-Tasten-Gamepad" -msgid "Gravis PC GamePad" -msgstr "Gravis PC GamePad" - msgid "2-button flight yoke" msgstr "2-Tasten-Steuerhorn" @@ -903,51 +921,6 @@ msgstr "Lenkrad (3-Achsen, 3-Tasten)" msgid "Steering wheel (3-axis, 4-button)" msgstr "Lenkrad (3-Achsen, 4-Tasten)" -msgid "CH Flightstick" -msgstr "CH Flightstick" - -msgid "CH Flightstick + CH Pedals" -msgstr "CH Flightstick + CH Pedals" - -msgid "CH Flightstick + CH Pedals Pro" -msgstr "CH Flightstick + CH Pedals Pro" - -msgid "CH Flightstick Pro" -msgstr "CH Flightstick Pro" - -msgid "CH Flightstick Pro + CH Pedals" -msgstr "CH Flightstick Pro + CH Pedale" - -msgid "CH Flightstick Pro + CH Pedals Pro" -msgstr "CH Flightstick Pro + CH Pedale Pro" - -msgid "CH Virtual Pilot" -msgstr "CH Virtual Pilot" - -msgid "CH Virtual Pilot + CH Pedals" -msgstr "CH Virtual Pilot + CH Pedale" - -msgid "CH Virtual Pilot + CH Pedals Pro" -msgstr "CH Virtual Pilot + CH Pedale Pro" - -msgid "CH Virtual Pilot Pro" -msgstr "CH Virtual Pilot Pro" - -msgid "CH Virtual Pilot Pro + CH Pedals" -msgstr "CH Virtual Pilot Pro + CH Pedale" - -msgid "CH Virtual Pilot Pro + CH Pedals Pro" -msgstr "CH Virtual Pilot Pro + CH Pedale Pro" - -msgid "Microsoft SideWinder Pad" -msgstr "Microsoft SideWinder Pad" - -msgid "Thrustmaster Flight Control System" -msgstr "Thrustmaster Flight Control System" - -msgid "Thrustmaster FCS + Rudder Control System" -msgstr "Thrustmaster FCS + Rudder Control System" - msgid "Thrustmaster Formula T1/T2 with adapter" msgstr "Thrustmaster Formula T1/T2 mit Adapter" @@ -1002,11 +975,17 @@ msgstr "Internes Gerät" msgid "&File" msgstr "&Datei" -msgid "&New machine..." -msgstr "&Neue Maschine..." +msgid "&New machine…" +msgstr "&Neue Maschine…" + +msgid "New machine…" +msgstr "Neue Maschine…" + +msgid "New machine" +msgstr "Neue Maschine" -msgid "&Check for updates..." -msgstr "&Auf Aktualisierungen prüfen..." +msgid "&Check for updates…" +msgstr "&Auf Aktualisierungen prüfen…" msgid "Exit" msgstr "Beenden" @@ -1176,8 +1155,8 @@ msgstr "Die ausgewählte Konfigurationsdatei konnte nicht eingelesen werden: %1" msgid "Use regular expressions in search box" msgstr "Benutze reguläre Ausdrücke in der Suche" -msgid "%1 machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" -msgstr "%1 Maschinen sind aktuell aktiv. Bist du sicher, dass du den VM Manager trotzdem schließen möchtest?" +msgid "%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" +msgstr "%n Maschinen sind aktuell aktiv. Bist du sicher, dass du den VM Manager trotzdem schließen möchtest?" msgid "Add new system wizard" msgstr "Assistent für ein neues System" @@ -1257,26 +1236,23 @@ msgstr "Anzeigename festlegen" msgid "Enter the new display name (blank to reset)" msgstr "Gebe den neuen Anzeigenamen ein (leer lassen zum Zurücksetzen)" -msgid "Change &display name..." -msgstr "&Anzeigename ändern..." +msgid "Change &display name…" +msgstr "&Anzeigename ändern…" -msgid "Context Menu" -msgstr "Kontextmenü" +msgid "&Open folder…" +msgstr "&Ordner öffnen…" -msgid "&Open folder..." -msgstr "&Ordner öffnen..." +msgid "Open p&rinter tray…" +msgstr "D&ruckerausgabe öffnen…" -msgid "Open p&rinter tray..." -msgstr "D&ruckerausgabe öffnen..." - -msgid "Set &icon..." -msgstr "&Symbol setzen..." +msgid "Set &icon…" +msgstr "&Symbol setzen…" msgid "Select an icon" msgstr "Wähle ein Symbol aus" -msgid "C&lone..." -msgstr "K&lonen..." +msgid "C&lone…" +msgstr "K&lonen…" msgid "Virtual machine \"%1\" (%2) will be cloned into:" msgstr "Virtuelle Maschine \"%1\" (%2) wird geklont werden nach:" @@ -1362,8 +1338,8 @@ msgstr "Keine Bildschirmaufnahme" msgid "Search" msgstr "Suche" -msgid "Searching for VMs..." -msgstr "Suche nach VMs..." +msgid "Searching for VMs…" +msgstr "Suche nach VMs…" msgid "Found %1" msgstr "Gefunden %1" @@ -1398,11 +1374,11 @@ msgstr "Festplatte (%1)" msgid "MFM/RLL or ESDI CD-ROM drives never existed" msgstr "MFM/RLL- oder ESDI-CD-ROM-Laufwerke existieren nicht" -msgid "Custom..." -msgstr "Angepasst..." +msgid "Custom…" +msgstr "Angepasst…" -msgid "Custom (large)..." -msgstr "Angepasst (groß)..." +msgid "Custom (large)…" +msgstr "Angepasst (groß)…" msgid "Add New Hard Disk" msgstr "Neue Festplatte hinzufügen" @@ -1521,21 +1497,6 @@ msgstr "Die Zeitstempel der Eltern- und der Kindesplatte stimmen nicht überein" msgid "Could not fix VHD timestamp." msgstr "Der Zeitstempel der VHD konnte nicht korrigiert werden." -msgid "MFM/RLL" -msgstr "MFM/RLL" - -msgid "XTA" -msgstr "XTA" - -msgid "ESDI" -msgstr "ESDI" - -msgid "IDE" -msgstr "IDE" - -msgid "ATAPI" -msgstr "ATAPI" - msgid "CD-ROM %1 (%2): %3" msgstr "CD-ROM %1 (%2): %3" @@ -1686,14 +1647,14 @@ msgstr "Tablet-Werkzeug" msgid "About &Qt" msgstr "Über &Qt" -msgid "&MCA devices..." -msgstr "MCA-Geräte..." +msgid "&MCA devices…" +msgstr "MCA-Geräte…" msgid "Show non-&primary monitors" msgstr "Nicht-primäre Monitore anzeigen" -msgid "Open screenshots &folder..." -msgstr "Ordner „screenshots“ ö&ffnen..." +msgid "Open screenshots &folder…" +msgstr "Ordner „screenshots“ ö&ffnen…" msgid "Appl&y fullscreen stretch mode when maximized" msgstr "Vollbild-S&treckmodus aktivieren, wenn das Fenster maximiert ist" @@ -1713,8 +1674,8 @@ msgstr "&Verbunden" msgid "Clear image &history" msgstr "&Abbildverlauf löschen" -msgid "Create..." -msgstr "Erstellen..." +msgid "Create…" +msgstr "Erstellen…" msgid "Host CD/DVD Drive (%1)" msgstr "Host-CD/DVD-Laufwerk (%1)" @@ -1755,8 +1716,8 @@ msgstr "Shader" msgid "Remove" msgstr "Entfernen" -msgid "Browse..." -msgstr "Durchsuchen..." +msgid "Browse…" +msgstr "Durchsuchen…" msgid "Couldn't create OpenGL context." msgstr "OpenGL-Kontext konnte nicht erstellt werden." @@ -1845,8 +1806,8 @@ msgstr "Serielle Schnittstelle 3 durchreichen" msgid "Serial port passthrough 4" msgstr "Serielle Schnittstelle 4 durchreichen" -msgid "Renderer &options..." -msgstr "Renderer-&Optionen..." +msgid "Renderer &options…" +msgstr "Renderer-&Optionen…" msgid "PC/XT Keyboard" msgstr "PC/XT-Tastatur" @@ -1899,8 +1860,8 @@ msgstr "3M MicroTouch (Seriell)" msgid "Default Baud rate" msgstr "Standard-Baudrate" -msgid "[COM] Standard Hayes-compliant Modem" -msgstr "[COM] Standard Hayes-kompatibles Modem" +msgid "Standard Hayes-compliant Modem" +msgstr "Standard Hayes-kompatibles Modem" msgid "Roland MT-32 Emulation" msgstr "Roland MT-32-Emulation" @@ -1983,6 +1944,9 @@ msgstr "IRQ des seriellen Ports" msgid "Parallel port IRQ" msgstr "IRQ des parallelen Ports" +msgid "Hard disk" +msgstr "Festplatte" + msgid "BIOS Revision" msgstr "BIOS-Revision" @@ -2058,9 +2022,6 @@ msgstr "MIDI-Durchgang" msgid "MIDI Clockout" msgstr "MIDI-Taktausgabe" -msgid "SoundFont" -msgstr "SoundFont" - msgid "Output Gain" msgstr "Ausgangsverstärkung" @@ -2853,9 +2814,6 @@ msgstr "Vollbild umschalten" msgid "Toggle UI in fullscreen" msgstr "UI im Vollbildmodus umschalten" -msgid "Screenshot" -msgstr "Bildschirmaufnahme" - msgid "Release mouse pointer" msgstr "Mauszeiger freigeben" @@ -2970,8 +2928,8 @@ msgstr "Download-Webseite besuchen" msgid "Update check" msgstr "Aktualisierungsprüfung" -msgid "Checking for updates..." -msgstr "Prüfe auf Aktualisierungen..." +msgid "Checking for updates…" +msgstr "Prüfe auf Aktualisierungen…" msgid "86Box Update" msgstr "86Box Aktualisierung" @@ -3009,8 +2967,8 @@ msgstr "Helligkeit" msgid "Sharpness" msgstr "Schärfe" -msgid "&CGA composite settings..." -msgstr "Optionen des &CGA-Composite-Modus..." +msgid "&CGA composite settings…" +msgstr "Optionen des &CGA-Composite-Modus…" msgid "CGA composite settings" msgstr "Optionen des CGA-Composite-Modus" @@ -3018,8 +2976,8 @@ msgstr "Optionen des CGA-Composite-Modus" msgid "Monitor EDID" msgstr "EDID des Monitors" -msgid "Export..." -msgstr "Exportieren..." +msgid "Export…" +msgstr "Exportieren…" msgid "Export EDID" msgstr "EDID exportieren" @@ -3044,3 +3002,24 @@ msgstr "Dunkel" msgid "Search:" msgstr "Suche:" + +msgid "Force interpretation" +msgstr "Erzwingen der Interpretation" + +msgid "Allow recompilation" +msgstr "Recompilierung zulassen" + +msgid "&Force interpretation" +msgstr "&Erzwingen der Interpretation" + +msgid "&Allow recompilation" +msgstr "Recompilierung &zulassen" + +msgid "&Fast forward" +msgstr "" + +msgid "Fast forward" +msgstr "" + +msgid "To change the system directory, stop all running machines." +msgstr "" diff --git a/src/qt/languages/el-GR.po b/src/qt/languages/el-GR.po new file mode 100644 index 00000000000..9243c24fb23 --- /dev/null +++ b/src/qt/languages/el-GR.po @@ -0,0 +1,3082 @@ +msgid "" +msgstr "" +"PO-Revision-Date: 2026-01-10 12:56+0000\n" +"Last-Translator: DimMan88 \n" +"Language-Team: Greek \n" +"Language: el-GR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.12.2\n" +"X-Language: el_GR\n" +"X-Source-Language: en_US\n" + +msgid "&Action" +msgstr "&Ενέργειες" + +msgid "&Keyboard requires capture" +msgstr "&Το πληκτρολόγιο απαιτεί αγκίστρωση" + +msgid "&Right CTRL is left ALT" +msgstr "&Αντιστοίχιση Right CTRL σε left ALT" + +msgid "&Hard reset" +msgstr "&Ολική επανεκκίνηση" + +msgid "&Ctrl+Alt+Del" +msgstr "&Ctrl+Alt+Del" + +msgid "Ctrl+Alt+&Esc" +msgstr "Ctrl+Alt+&Esc" + +msgid "&Pause" +msgstr "&Παύση" + +msgid "Pause" +msgstr "Παύση" + +msgid "Re&sume" +msgstr "Συ&νέχια" + +msgid "E&xit" +msgstr "Έ&ξοδος" + +msgid "&View" +msgstr "&Προβολή" + +msgid "&Hide status bar" +msgstr "&Απόκρυψη γραμμής κατάστασης" + +msgid "Hide &toolbar" +msgstr "Απόκρυψη &γραμμής εργαλείων" + +msgid "&Resizeable window" +msgstr "&Προσαρμόσιμο παράθυρο" + +msgid "R&emember size && position" +msgstr "Α&πομνήμευση μεγέθους && θέσης" + +msgid "Remember size && position" +msgstr "Απομνήμευση μεγέθους && θέσης" + +msgid "Re&nderer" +msgstr "Re&nderer" + +msgid "&Qt (Software)" +msgstr "&Qt (Software)" + +msgid "Open&GL (3.0 Core)" +msgstr "Open&GL (3.0 Core)" + +msgid "&VNC" +msgstr "&VNC" + +msgid "Specify &dimensions…" +msgstr "Ορισμός &διαστάσεων…" + +msgid "Force &4:3 display ratio" +msgstr "Εξαναγκασμός &αναλογίας οθόνης 4:3" + +msgid "&Window scale factor" +msgstr "&Συντελεστής κλίμακας παραθύρου" + +msgid "&0.5x" +msgstr "&0.5x" + +msgid "&1x" +msgstr "&1x" + +msgid "1.&5x" +msgstr "1.&5x" + +msgid "&2x" +msgstr "&2x" + +msgid "&3x" +msgstr "&3x" + +msgid "&4x" +msgstr "&4x" + +msgid "&5x" +msgstr "&5x" + +msgid "&6x" +msgstr "&6x" + +msgid "&7x" +msgstr "&7x" + +msgid "&8x" +msgstr "&8x" + +msgid "Fi<er method" +msgstr "Τύ&πος φιλτραρίσματος" + +msgid "&Nearest" +msgstr "&Nearest" + +msgid "&Linear" +msgstr "&Linear" + +msgid "Hi&DPI scaling" +msgstr "Κλ&ίμακα HiDPI" + +msgid "&Fullscreen" +msgstr "&Πλήρης οθόνη" + +msgid "Fullscreen &stretch mode" +msgstr "Πλήρης οθόνη &σε λειτουργία τεντώματος" + +msgid "&Full screen stretch" +msgstr "&Τέντωμα πλήρους οθόνης" + +msgid "&4:3" +msgstr "&4:3" + +msgid "&Square pixels (Keep ratio)" +msgstr "&Τετράγωνα εικονοστοιχεία (Διατήρηση αναλογίας)" + +msgid "&Integer scale" +msgstr "&Aκέραια κλίμακα" + +msgid "4:&3 Integer scale" +msgstr "Aκέραια κλίμακα 4:&3" + +msgid "EGA/(S)&VGA settings" +msgstr "Ρυθμίσε&ις EGA/(S)VGA" + +msgid "&Inverted VGA monitor" +msgstr "&Αντεστραμμένο VGA monitor" + +msgid "VGA screen &type" +msgstr "Τύπος οθόνης& VGA" + +msgid "RGB &Color" +msgstr "Χρώματα RGB" + +msgid "RGB (no brown)" +msgstr "RGB (χωρίς το καφέ)" + +msgid "&RGB Grayscale" +msgstr "&RGB κλίμακας γκρι" + +msgid "Generic RGBI color monitor" +msgstr "Γενική έγχρωμη οθόνη RGBI" + +msgid "&Amber monitor" +msgstr "&Κεχριμπάρι οθόνη" + +msgid "&Green monitor" +msgstr "&Πράσινη οθόνη" + +msgid "&White monitor" +msgstr "&Λευκή οθόνη" + +msgid "Grayscale &conversion type" +msgstr "Τύπος μετα&τροπής κλίμακας του γκρι" + +msgid "BT&601 (NTSC/PAL)" +msgstr "BT&601 (NTSC/PAL)" + +msgid "BT&709 (HDTV)" +msgstr "BT&709 (HDTV)" + +msgid "&Average" +msgstr "&Σχετικό" + +msgid "CGA/PCjr/Tandy/E&GA/(S)VGA overscan" +msgstr "Υπερσάρωση CGA/PCjr/Tandy/E&GA/(S)VGA" + +msgid "Change contrast for &monochrome display" +msgstr "Αλλαγή αντίθεσης γι&α μονόχρωμη οθόνη" + +msgid "&Media" +msgstr "&Μέσα" + +msgid "&Tools" +msgstr "&Εργαλεία" + +msgid "&Settings…" +msgstr "&Ρυθμίσεις…" + +msgid "Settings…" +msgstr "Ρυθμίσεις…" + +msgid "&Update status bar icons" +msgstr "&Ανανέωση εικονιδίων γραμμής κατάστασης" + +msgid "Take s&creenshot" +msgstr "Λήψη σ&τιγμιότυπου" + +msgid "Take screenshot" +msgstr "Λήψη στιγμιότυπου" + +msgid "Take &raw screenshot" +msgstr "Λήψη &αρχικού στιγμιότυπου" + +msgid "Take raw screenshot" +msgstr "Λήψη αρχικού στιγμιότυπου" + +msgid "C&opy screenshot" +msgstr "&Αντιγραφή στιγμιότυπου" + +msgid "Copy screenshot" +msgstr "Αντιγραφή στιγμιότυπου" + +msgid "Copy r&aw screenshot" +msgstr "Αντιγραφή α&ρχικού στιγμιότυπου" + +msgid "Copy raw screenshot" +msgstr "Αντιγραφή αρχικού στιγμιότυπου" + +msgid "S&ound" +msgstr "Ή&χος" + +msgid "&Preferences…" +msgstr "&Προτιμήσεις…" + +msgid "Enable &Discord integration" +msgstr "Ενεργοποίηση διασύνδεσης &Discord" + +msgid "Sound &gain…" +msgstr "&Ενίσχυση ήχου…" + +msgid "Begin trace" +msgstr "Αρχλη καταγραφής" + +msgid "End trace" +msgstr "Τέλος καταγραφής" + +msgid "&Help" +msgstr "&Βοήθεια" + +msgid "&Documentation…" +msgstr "&Εγχειρίδια…" + +msgid "&About 86Box…" +msgstr "&Σχετικά με το 86Box…" + +msgid "&New image…" +msgstr "&Δημιουργία εικόνας…" + +msgid "&Existing image…" +msgstr "&Υπάρχουσα εικόνα…" + +msgid "Existing image (&Write-protected)…" +msgstr "Υπάρχουσα εικόνα (&Προστασία-εγγραφής)…" + +msgid "&Record" +msgstr "&Καταγραφή" + +msgid "&Play" +msgstr "&Αναπαραγωγή" + +msgid "&Rewind to the beginning" +msgstr "&Γύρισμα στην αρχή" + +msgid "&Fast forward to the end" +msgstr "&Γρήγορα μπροστά στο τέλος" + +msgid "E&ject" +msgstr "&Εξαγωγή" + +msgid "&Image…" +msgstr "&Εικόνα…" + +msgid "E&xport to 86F…" +msgstr "&Εξαγωγή σε 86F…" + +msgid "&Mute" +msgstr "&Σίγαση" + +msgid "E&mpty" +msgstr "&Κενό" + +msgid "Reload previous image" +msgstr "Επαναφώρτωση προηγύμενης εικόνας" + +msgid "&Folder…" +msgstr "&Φάκελος…" + +msgid "Preferences" +msgstr "Προτιμήσεις" + +msgid "Sound Gain" +msgstr "Ενίσχυση Ήχου" + +msgid "New Image" +msgstr "Δημιουργία εικόνας" + +msgid "Settings" +msgstr "Ρυθμίσεις" + +msgid "Specify Main Window Dimensions" +msgstr "Ορισμός Διαστάσεων Κύριου Παραθύρου" + +msgid "OK" +msgstr "ΟΚ" + +msgid "Cancel" +msgstr "Άκυρο" + +msgid "&Default" +msgstr "&Προεπιλογή" + +msgid "Language:" +msgstr "Γλώσσα:" + +msgid "Gain" +msgstr "Ενίσχυση" + +msgid "File name:" +msgstr "Όνομα αρχείου:" + +msgid "Disk size:" +msgstr "Μέγεθος δίσκου:" + +msgid "RPM mode:" +msgstr "Λειτουργία RPM:" + +msgid "Progress:" +msgstr "Πρόοδος:" + +msgid "Width:" +msgstr "Πλάτος:" + +msgid "Height:" +msgstr "Ύψος:" + +msgid "Lock to this size" +msgstr "Κλείδωμα σε αυτό το μέγεθος" + +msgid "Machine type:" +msgstr "Τύπος συστήματος:" + +msgid "Machine:" +msgstr "Σύστημα:" + +msgid "Configure" +msgstr "Προσαρμογή" + +msgid "CPU:" +msgstr "CPU:" + +msgid "CPU type:" +msgstr "Τύπος CPU:" + +msgid "Speed:" +msgstr "Ταχύτητα:" + +msgid "Frequency:" +msgstr "Συχνότητα:" + +msgid "FPU:" +msgstr "FPU:" + +msgid "Wait states:" +msgstr "Καταστάσεις αναμονής:" + +msgid "MB" +msgstr "MB" + +msgid "Memory:" +msgstr "Μνήμη:" + +msgid "Time synchronization" +msgstr "Συγχρονισμός ώρας" + +msgid "Disabled" +msgstr "Ανενεργό" + +msgid "Enabled (local time)" +msgstr "Ενεργό (τοπική ώρα)" + +msgid "Enabled (UTC)" +msgstr "Ενεργό (UTC)" + +msgid "Dynamic Recompiler" +msgstr "Dynamic Recompiler" + +msgid "CPU frame size" +msgstr "Μέγεθος πλαισίου CPU" + +msgid "Larger frames (less smooth)" +msgstr "Μεγαλύτερα πλαίσια (λιγότερο ομαλό)" + +msgid "Smaller frames (smoother)" +msgstr "Μικρότερα πλαίσια (πιο ομαλό)" + +msgid "Video:" +msgstr "Κάρτα γραφικών:" + +msgid "Video #2:" +msgstr "Κάρτα γραφικών #2:" + +msgid "Voodoo 1 or 2 Graphics" +msgstr "Γραφικά Voodoo 1 ή 2" + +msgid "IBM 8514/A Graphics" +msgstr "Γραφικά IBM 8514/A" + +msgid "XGA Graphics" +msgstr "Γραφικά XGA" + +msgid "IBM PS/55 Display Adapter Graphics" +msgstr "Προσαρμογέας Γραφικών IBM PS/55" + +msgid "Keyboard:" +msgstr "Πληκτρολόγιο:" + +msgid "Keyboard" +msgstr "Πληκτρολόγιο" + +msgid "Mouse:" +msgstr "Ποντίκι:" + +msgid "Mouse" +msgstr "Ποντίκι" + +msgid "Joystick:" +msgstr "Joystick:" + +msgid "Joystick" +msgstr "Joystick" + +msgid "Joystick 1…" +msgstr "Joystick 1…" + +msgid "Joystick 2…" +msgstr "Joystick 2…" + +msgid "Joystick 3…" +msgstr "Joystick 3…" + +msgid "Joystick 4…" +msgstr "Joystick 4…" + +msgid "Sound card #1:" +msgstr "Κάρτα ήχου #1:" + +msgid "Sound card #2:" +msgstr "Κάρτα ήχου #2:" + +msgid "Sound card #3:" +msgstr "Κάρτα ήχου #3:" + +msgid "Sound card #4:" +msgstr "Κάρτα ήχου #4:" + +msgid "MIDI Out Device:" +msgstr "Συσκευή MIDI Out:" + +msgid "MIDI In Device:" +msgstr "Συσκευή MIDI In:" + +msgid "MIDI Out:" +msgstr "MIDI Out:" + +msgid "Standalone MPU-401" +msgstr "Ξέχωρο MPU-401" + +msgid "Use FLOAT32 sound" +msgstr "Χρήση ήχου FLOAT32" + +msgid "FM synth driver" +msgstr "Οδηγός FM synth" + +msgid "Nuked (more accurate)" +msgstr "Nuked (πιο ακριβές)" + +msgid "YMFM (faster)" +msgstr "YMFM (γρήγορο)" + +msgid "COM1 Device:" +msgstr "Συσκευή COM1:" + +msgid "COM2 Device:" +msgstr "Συσκευή COM2:" + +msgid "COM3 Device:" +msgstr "Συσκευή COM3:" + +msgid "COM4 Device:" +msgstr "Συσκευή COM4:" + +msgid "LPT1 Device:" +msgstr "Συσκευή LPT1:" + +msgid "LPT2 Device:" +msgstr "Συσκευή LPT2:" + +msgid "LPT3 Device:" +msgstr "Συσκευή LPT3:" + +msgid "LPT4 Device:" +msgstr "Συσκευή LPT4:" + +msgid "Internal LPT ECP DMA:" +msgstr "Εσωτερικό LPT ECP DMA:" + +msgid "Serial port 1" +msgstr "Σειριακή θύρα 1" + +msgid "Serial port 2" +msgstr "Σειριακή θύρα 2" + +msgid "Serial port 3" +msgstr "Σειριακή θύρα 3" + +msgid "Serial port 4" +msgstr "Σειριακή θύρα 4" + +msgid "Parallel port 1" +msgstr "Παράλληλη θύρα 1" + +msgid "Parallel port 2" +msgstr "Παράλληλη θύρα 2" + +msgid "Parallel port 3" +msgstr "Παράλληλη θύρα 3" + +msgid "Parallel port 4" +msgstr "Παράλληλη θύρα 4" + +msgid "Floppy disk controller:" +msgstr "Ελεγκτής δισκέτας:" + +msgid "CD-ROM controller:" +msgstr "Ελεγκτής CD-ROM:" + +msgid "Tertiary IDE Controller" +msgstr "Τριτογενής Ελεγκτής IDE" + +msgid "Quaternary IDE Controller" +msgstr "Τεταρτογενής Ελεγκτής IDE" + +msgid "Hard disk controllers" +msgstr "Ελεγκτές σκληρού δίσκου" + +msgid "SCSI controllers" +msgstr "Ελεγκτές SCSI" + +msgid "Controller 1:" +msgstr "Ελεγκτής 1:" + +msgid "Controller 2:" +msgstr "Ελεγκτής 2:" + +msgid "Controller 3:" +msgstr "Ελεγκτής 3:" + +msgid "Controller 4:" +msgstr "Ελεγκτής 4:" + +msgid "Cassette" +msgstr "Κασέτα" + +msgid "Hard disks:" +msgstr "Σκληροί δίσκοι:" + +msgid "Firmware Version" +msgstr "Έκδοση Firmware" + +msgid "&New…" +msgstr "&Δημιουργία…" + +msgid "&Existing…" +msgstr "&Υπάρχων…" + +msgid "&Remove" +msgstr "&Κατάργηση" + +msgid "Bus:" +msgstr "Δίαυλος:" + +msgid "Channel:" +msgstr "Κανάλι:" + +msgid "ID:" +msgstr "ID:" + +msgid "Sectors:" +msgstr "Τομείς:" + +msgid "Heads:" +msgstr "Κεφαλές:" + +msgid "Cylinders:" +msgstr "Κύλινδροι:" + +msgid "Size (MB):" +msgstr "Μέγεθος (MB):" + +msgid "Type:" +msgstr "Τύπος:" + +msgid "Image Format:" +msgstr "Τύπος Εικόνας:" + +msgid "Block Size:" +msgstr "Block Size:" + +msgid "Floppy drives:" +msgstr "Οδηγοί δισκέτας:" + +msgid "Turbo timings" +msgstr "Χρονισμοί Turbo" + +msgid "Check BPB" +msgstr "Έλεγχος BPB" + +msgid "CD-ROM drives:" +msgstr "Οδηγοί CD-ROM:" + +msgid "MO drives:" +msgstr "Οδηγοί MO:" + +msgid "MO:" +msgstr "MO:" + +msgid "Removable disks:" +msgstr "Αφαιρούμενοι δίσκοι:" + +msgid "Removable disk drives:" +msgstr "Οδηγοί αφαιρούμενων δίσκων:" + +msgid "ZIP 250" +msgstr "ZIP 250" + +msgid "ISA RTC:" +msgstr "ISA RTC:" + +msgid "ISA Memory Expansion" +msgstr "Επέκταση Μνήμης ISA" + +msgid "ISA ROM Cards" +msgstr "Κάρτες ROM ISA" + +msgid "Card 1:" +msgstr "Κάρτα 1:" + +msgid "Card 2:" +msgstr "Κάρτα 2:" + +msgid "Card 3:" +msgstr "Κάρτα 3:" + +msgid "Card 4:" +msgstr "Κάρτα 4:" + +msgid "Generic ISA ROM Board" +msgstr "Γενική ISA ROM πλακέτα" + +msgid "Generic Dual ISA ROM Board" +msgstr "Γενική Διπλή ISA ROM πλακέτα" + +msgid "Generic Quad ISA ROM Board" +msgstr "Γενική Τετραπλή ISA ROM πλακέτα" + +msgid "ISABugger device" +msgstr "Συσκευή ISABugger" + +msgid "POST card" +msgstr "κάρτα POST" + +msgid "Error" +msgstr "Σφάλμα" + +msgid "Fatal error" +msgstr "Οριστικό σφάλμα" + +msgid " - PAUSED" +msgstr " - ΣΤΑΜΑΤΗΜΕΝΟ" + +msgid "Speed" +msgstr "Ταχύτητα" + +msgid "Removable disk %1 (%2): %3" +msgstr "Αφαιρούμενος δίσκος %1 (%2): %3" + +msgid "&Removable disk %1 (%2): %3" +msgstr "&Αφαιρούμενος δίσκος %1 (%2): %3" + +msgid "Removable disk images" +msgstr "Εικόνες αφαιρούμενων δίσκων" + +msgid "Image %1" +msgstr "Εικόνα %1" + +msgid "86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory." +msgstr "Το 86Box δεν μπόρεσε να εντοπίσει καμία ROM.\n\nΠαρακαλώ κατεβάστε το πακέτο ROM και εξάγετέ το στον κατάλογο \"roms\"." + +msgid "(empty)" +msgstr "(κενό)" + +msgid "All files" +msgstr "Όλα τα αρχεία" + +msgid "Turbo" +msgstr "Turbo" + +msgid "On" +msgstr "On" + +msgid "Off" +msgstr "Off" + +msgid "All images" +msgstr "Όλες οι εικόνες" + +msgid "Basic sector images" +msgstr "Εικόνες βασικού τόμου" + +msgid "Surface images" +msgstr "Εικόνες επιφάνειας" + +msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." +msgstr "Το σύστημα \"%hs\" δεν είναι διαθέσιμο λόγω έλλειψης των ROMs στον κατάλογο roms/machines. Αλλάξτε σε διαθέσιμο σύστημα." + +msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." +msgstr "Η κάρτα γραφικών \"%hs\" δεν είναι διαθέσιμη λόγω έλλειψης των ROMs στον κατάλογο roms/video. Αλλάξτε σε διαθέσιμη κάρτα γραφικών." + +msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." +msgstr "Η κάρτα γραφικών #2 \"%hs\" δεν είναι διαθέσιμη λόγω έλλειψης των ROMs στον κατάλογο roms/video. Αλλάξτε σε διαθέσιμη κάρτα γραφικών." + +msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." +msgstr "Η συσκευή \"%hs\" δεν είναι διαθέσιμη λόγω έλλειψης των ROMs. Παράκαμψη συσκευής." + +msgid "Machine" +msgstr "Σύστημα" + +msgid "Display" +msgstr "Οθόνη" + +msgid "Input devices" +msgstr "Συσκευές εισόδου" + +msgid "Sound" +msgstr "Ήχος" + +msgid "Network" +msgstr "Δίκτυο" + +msgid "Ports (COM & LPT)" +msgstr "Θύρες (COM & LPT)" + +msgid "Ports" +msgstr "Θύρες" + +msgid "Serial ports:" +msgstr "Σειριακές θύρες:" + +msgid "Parallel ports:" +msgstr "Παράλληλες θύρες:" + +msgid "Storage controllers" +msgstr "Ελεγκτές αποθήκευσης" + +msgid "Hard disks" +msgstr "Σκληροί δίσκοι" + +msgid "Disks:" +msgstr "Δίσκοι:" + +msgid "Floppy:" +msgstr "Δισκέτες:" + +msgid "Controllers:" +msgstr "Ελεγκτές:" + +msgid "Floppy & CD-ROM drives" +msgstr "Οδηγοί Δισκέτας & CD-ROM" + +msgid "Other removable devices" +msgstr "Άλλες αφαιρούμενες συσκευές" + +msgid "Other peripherals" +msgstr "Άλλα περιφερειακά" + +msgid "Other devices" +msgstr "Άλλες συσκευές" + +msgid "Click to capture mouse" +msgstr "Κλικ για αγκίστρωση ποντικιού" + +msgid "Press %1 to release mouse" +msgstr "Πατήστε %1 για απαγκίστρωση ποντικιού" + +msgid "Press %1 or middle button to release mouse" +msgstr "Πατήστε %1 ή το μεσαίο κουμπί για απαγκίστρωση ποντικιού" + +msgid "Bus" +msgstr "Δίαυλος" + +msgid "File" +msgstr "Αρχείο" + +msgid "C" +msgstr "C" + +msgid "H" +msgstr "H" + +msgid "S" +msgstr "S" + +msgid "KB" +msgstr "KB" + +msgid "Default" +msgstr "Προεπιλογή" + +msgid "%1 Wait state(s)" +msgstr "%1 Κατάσταση αναμονής(ών)" + +msgid "Type" +msgstr "Τύπος" + +msgid "No PCap devices found" +msgstr "Δεν βέθηκαν PCap συσκευές" + +msgid "Invalid PCap device" +msgstr "Μη έγκυρη PCap συσκευή" + +msgid "Generic paddle controller(s)" +msgstr "Generic paddle controller(s)" + +msgid "2-axis, 1-button joystick(s)" +msgstr "2-axis, 1-button joystick(s)" + +msgid "2-axis, 2-button joystick(s)" +msgstr "2-axis, 2-button joystick(s)" + +msgid "2-axis, 3-button joystick" +msgstr "2-axis, 3-button joystick" + +msgid "2-axis, 4-button joystick" +msgstr "2-axis, 4-button joystick" + +msgid "2-axis, 6-button joystick" +msgstr "2-axis, 6-button joystick" + +msgid "2-axis, 8-button joystick" +msgstr "2-axis, 8-button joystick" + +msgid "3-axis, 2-button joystick" +msgstr "3-axis, 2-button joystick" + +msgid "3-axis, 3-button joystick" +msgstr "3-axis, 3-button joystick" + +msgid "3-axis, 4-button joystick" +msgstr "3-axis, 4-button joystick" + +msgid "4-axis, 2-button joystick" +msgstr "4-axis, 2-button joystick" + +msgid "4-axis, 3-button joystick" +msgstr "4-axis, 3-button joystick" + +msgid "4-axis, 4-button joystick" +msgstr "4-axis, 4-button joystick" + +msgid "2-button gamepad(s)" +msgstr "2-button gamepad(s)" + +msgid "3-button gamepad" +msgstr "3-button gamepad" + +msgid "4-button gamepad" +msgstr "4-button gamepad" + +msgid "6-button gamepad" +msgstr "6-button gamepad" + +msgid "2-button flight yoke" +msgstr "2-button flight yoke" + +msgid "3-button flight yoke" +msgstr "3-button flight yoke" + +msgid "4-button flight yoke" +msgstr "4-button flight yoke" + +msgid "2-button flight yoke with throttle" +msgstr "2-button flight yoke with throttle" + +msgid "3-button flight yoke with throttle" +msgstr "3-button flight yoke with throttle" + +msgid "4-button flight yoke with throttle" +msgstr "4-button flight yoke with throttle" + +msgid "Steering wheel (3-axis, 2-button)" +msgstr "Steering wheel (3-axis, 2-button)" + +msgid "Steering wheel (3-axis, 3-button)" +msgstr "Steering wheel (3-axis, 3-button)" + +msgid "Steering wheel (3-axis, 4-button)" +msgstr "Steering wheel (3-axis, 4-button)" + +msgid "Thrustmaster Formula T1/T2 with adapter" +msgstr "Thrustmaster Formula T1/T2 with adapter" + +msgid "Thrustmaster Formula T1/T2 without adapter" +msgstr "Thrustmaster Formula T1/T2 without adapter" + +msgid "None" +msgstr "Κανένα" + +msgid "%1 MB (CHS: %2, %3, %4)" +msgstr "%1 MB (CHS: %2, %3, %4)" + +msgid "Floppy %1 (%2): %3" +msgstr "Δισκέτα %1 (%2): %3" + +msgid "&Floppy %1 (%2): %3" +msgstr "&Δισκέτα %1 (%2): %3" + +msgid "Advanced sector images" +msgstr "Εικόνες προχωρημένου τομέα" + +msgid "Flux images" +msgstr "Εικόνες Flux" + +msgid "Are you sure you want to hard reset the emulated machine?" +msgstr "" +"Είστε σίγουρος οτι θέλετε να κάνετε ολική επανεκκίνηση του εξομειωμένου " +"σύστηματος;" + +msgid "Are you sure you want to exit 86Box?" +msgstr "Είστε σίγουρος για την έξοδο απο το 86Box;" + +msgid "Unable to initialize Ghostscript" +msgstr "Αδυναμία αρχικοποίησης Ghostscript" + +msgid "Unable to initialize GhostPCL" +msgstr "Αδυναμία αρχικοποίησης GhostPCL" + +msgid "MO %1 (%2): %3" +msgstr "MO %1 (%2): %3" + +msgid "&MO %1 (%2): %3" +msgstr "&MO %1 (%2): %3" + +msgid "MO images" +msgstr "Εικόνες MO" + +msgid "Welcome to 86Box!" +msgstr "Καλως ορίσατε στο 86Box!" + +msgid "Internal device" +msgstr "Εσωτερική συσκευή" + +msgid "&File" +msgstr "&Αρχείο" + +msgid "&New machine…" +msgstr "&Νέα μηχανή…" + +msgid "New machine…" +msgstr "Νέα μηχανή…" + +msgid "New machine" +msgstr "Νέα μηχανή" + +msgid "&Check for updates…" +msgstr "&Έλεγχος για ενημερώσεις…" + +msgid "Exit" +msgstr "Έξοδος" + +msgid "No ROMs found" +msgstr "Δεν βρέθηκαν ROMs" + +msgid "Do you want to save the settings?" +msgstr "Επιθυμείτε να αποθηκεύσετε τις ρυθμίσεις;" + +msgid "This will hard reset the emulated machine." +msgstr "Αυτό θα οδηγήσει σε ολική επανεκκίνηση της εξομοιωμένης μηχανής." + +msgid "Save" +msgstr "Αποθήκευση" + +msgid "About %1" +msgstr "Σχετικά με το %1" + +msgid "An emulator of old computers\n\nAuthors: Miran Grča (OBattler), RichardG867, Jasmine Iwanek, TC1995, coldbrewed, Teemu Korhonen (Manaatti), Joakim L. Gilje, Adrien Moulin (elyosh), Daniel Balsom (gloriouscow), Cacodemon345, Fred N. van Kempen (waltje), Tiseno100, reenigne, and others.\n\nWith previous core contributions from Sarah Walker, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." +msgstr "Εξομειωτής παλαιών υπολογιστών\n\nAuthors: Miran Grča (OBattler), RichardG867, Jasmine Iwanek, TC1995, coldbrewed, Teemu Korhonen (Manaatti), Joakim L. Gilje, Adrien Moulin (elyosh), Daniel Balsom (gloriouscow), Cacodemon345, Fred N. van Kempen (waltje), Tiseno100, reenigne, and others.\n\nWith previous core contributions from Sarah Walker, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." + +msgid "Hardware not available" +msgstr "Μη διαθέσιμο υλικό" + +msgid "Make sure %1 is installed and that you are on a %1-compatible network connection." +msgstr "Βεβαιωθήτε οτι το %1 είναι εγκατεστημένο και οτι είστε σε %1-συμβατό δίκτυο." + +msgid "Invalid configuration" +msgstr "Μη έγκυρη προσαρμογή" + +msgid "%1 is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." +msgstr "%1 απαιτείται για αυτόματη μετατροπή αρχείων PostScript σε PDF.\n\nΈγγραφα που στέλνονται στον γενικό εκτυπωτή PostScript θα αποθηκεύονται ως αρχεία PostScript (.ps)." + +msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files." +msgstr "%1 απαιτείται για αυτόματη μετατροπή αρχείων PCL σε PDF.\n\nΈγγραφα που στέλνονται στον γενικό εκτυπωτή PCL θα αποθηκεύονται ως αρχεία Printer Command Language (.pcl)." + +msgid "Don't show this message again" +msgstr "Να μην ξαναεμφανιστεί αυτό το μήνυμα" + +msgid "Don't exit" +msgstr "Παραμονή" + +msgid "Reset" +msgstr "Επαναφορά" + +msgid "Don't reset" +msgstr "Οχι επαναφορά" + +msgid "CD-ROM images" +msgstr "Εικόνες CD-ROM" + +msgid "%1 Device Configuration" +msgstr "%1 Προσαρμογή Συσκευής" + +msgid "Monitor in sleep mode" +msgstr "Οθόνη σε λειτουργία αναμονής" + +msgid "GLSL shaders" +msgstr "GLSL shaders" + +msgid "You are loading an unsupported configuration" +msgstr "Προσπαθείτε να φορτώσετε μη υποστηριζόμενη προσαρμογή" + +msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." +msgstr "" +"Το φιλτράρισμα τύπου CPU βασισμένο στην επιλεγμένη μηχανή είναι " +"απενεργοποιημένο για αυτήν την εξομειωμένη μηχανή.\n" +"\n" +"Αυτό δίνει την δυνατότητα να επιλέξετε CPU που δεν είναι συμβατός με την " +"επιλεγμένη μηχανή. Παρ'όλ' αυτά υπάρχει περίτωση να έχετε ασυμβατότητες με " +"το BIOS της μηχανής ή άλλο λογισμικό.\n" +"\n" +"Ενεργοποιώντας αυτή την ρύθμιση η οποία δεν υποστηρίζεται επίσημα και οι " +"οποιεσδήποτε αναφορές σφαλμάτων θα κλείνουν ως μη έκγυρες." + +msgid "Continue" +msgstr "Συνέχεια" + +msgid "Cassette: %1" +msgstr "Κασέτα: %1" + +msgid "C&assette: %1" +msgstr "Κ&ασέτα: %1" + +msgid "Cassette images" +msgstr "Εικόνες κασέτας" + +msgid "Cartridge %1: %2" +msgstr "Κασέτα δεδομένων %1: %2" + +msgid "Car&tridge %1: %2" +msgstr "Car&tridge %1: %2" + +msgid "Cartridge images" +msgstr "Εικόνες κασέτας δεδομένων" + +msgid "Resume execution" +msgstr "Συνέχεια εκτέλεσης" + +msgid "Pause execution" +msgstr "Παύση εκτέλεσης" + +msgid "Ctrl+Alt+Del" +msgstr "Ctrl+Alt+Del" + +msgid "Press Ctrl+Alt+Del" +msgstr "Πατήστε Ctrl+Alt+Del" + +msgid "Press Ctrl+Alt+Esc" +msgstr "Πατήστε Ctrl+Alt+Esc" + +msgid "Hard reset" +msgstr "Ολική επανεκκίνηση" + +msgid "Force shutdown" +msgstr "Εξαναγκασμός τερματισμού" + +msgid "Start" +msgstr "Εκκίνηση" + +msgid "&Force shutdown" +msgstr "&Εξαναγκασμός τερματισμού" + +msgid "&Start" +msgstr "&Εκκίνηση" + +msgid "Not running" +msgstr "Ανενεργή" + +msgid "Running" +msgstr "Σε λειτουργία" + +msgid "Paused" +msgstr "Σε παύση" + +msgid "Waiting" +msgstr "Αναμονή" + +msgid "Powered Off" +msgstr "Κλειστή" + +msgid "%n running" +msgstr "%n τρέχει" + +msgid "%n paused" +msgstr "%n σε παύση" + +msgid "%n waiting" +msgstr "%n σε αναμονή" + +msgid "%1 total" +msgstr "%1 σύνολο" + +msgid "VMs: %1" +msgstr "VMs: %1" + +msgid "System Directory:" +msgstr "Κατάλογος Συστήματος:" + +msgid "Choose directory" +msgstr "Επιλέξτε κατάλογο" + +msgid "Choose configuration file" +msgstr "Επιλέξτε αρχείο προσαρμογής" + +msgid "86Box configuration files (86box.cfg)" +msgstr "Αρχεία προσαρμογής 86Box (86box.cfg)" + +msgid "Configuration read failed" +msgstr "Αποτυχία ανάγνωσης προσαρμογής" + +msgid "Unable to open the selected configuration file for reading: %1" +msgstr "Αδυναμία ανοίγματος επιλεγμένου αρχείου προσαρμογής για ανάγνωση: %1" + +msgid "Use regular expressions in search box" +msgstr "Χρήση συχνών εκφράσεων στην αναζήτηση" + +msgid "%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" +msgstr "%n μηχανής(ών) είναι εν ενεργεία. Είστε σίγουγος για την έξοδο απο το VM manager;" + +msgid "Add new system wizard" +msgstr "Οδηγός προσθήκης νέο συστήματος" + +msgid "Introduction" +msgstr "Παρουσίαση" + +msgid "This will help you add a new system to 86Box." +msgstr "Αυτός ο οδηγός θα σας βοηθήσει να εισάγετε νέο σύστημα στο 86Box." + +msgid "New configuration" +msgstr "Νέα προσαρμογή" + +msgid "Complete" +msgstr "Ολοκληρώθηκε" + +msgid "The wizard will now launch the configuration for the new system." +msgstr "Ο οδηγός θα εκκινήσει τώρα την προσαρμογή για το νέο σύστημα." + +msgid "Use existing configuration" +msgstr "Χρήση υπάρχουσας προσαρμογής" + +msgid "Type some notes here" +msgstr "Κρατήστε σημειώσεις εδώ" + +msgid "Paste the contents of the existing configuration file into the box below." +msgstr "Επικόλληση των περιεχομένων υπάρχον αρχείου προσαρμογής στο παρακάτω πλαίσιο." + +msgid "Load configuration from file" +msgstr "Φόρτωση προσαρμογής απο αρχείο" + +msgid "System name" +msgstr "Όνομα συστήματος" + +msgid "System name:" +msgstr "Όνομα συστήματος:" + +msgid "System name cannot contain certain characters" +msgstr "Το όνομα συστήματος δεν πρέπει να περιλαμβάνει ορισμένους χαρακτήρες" + +msgid "System name already exists" +msgstr "Το όνομα συστήματος υπάρχει ήδη" + +msgid "Please enter a directory for the system" +msgstr "Παρακαλώ ορίστε κατάλογο για το σύστημα" + +msgid "Directory does not exist" +msgstr "Ο κατάλογος δεν υπάρχει" + +msgid "A new directory for the system will be created in the selected directory above" +msgstr "Ένας νέος κατάλογος για το σύστημα θα δημιουργηθεί στον παραπάνω επιλεγμένο κατάλογο" + +msgid "System location:" +msgstr "Τοποθεσία συστήματος:" + +msgid "System name and location" +msgstr "Όνομα και τοποθεσία συστήματος" + +msgid "Enter the name of the system and choose the location" +msgstr "Εισάγετε το όνομα συστήματος και επιλέξτε τοποθεσία" + +msgid "Enter the name of the system" +msgstr "Εισάγετε το όνομα συστήματος" + +msgid "Please enter a system name" +msgstr "Παρακαλώ εισάγετε ένα όνομα συστήματος" + +msgid "Display name (optional):" +msgstr "Εμφανιζόμενο όνομα (προαιρετικό):" + +msgid "Display name:" +msgstr "Εμφανιζόμενο όνομα:" + +msgid "Set display name" +msgstr "Ορισμός ονόματος εμφάνισης" + +msgid "Enter the new display name (blank to reset)" +msgstr "Εισάγετε το νέο όνομα εμφάνισης (κενό για επαναφορά)" + +msgid "Change &display name…" +msgstr "Αλλαγή &ονόματος εμφάνισης…" + +msgid "&Open folder…" +msgstr "&Άνοιγμα φακέλου…" + +msgid "Open p&rinter tray…" +msgstr "Άνοιγμα δίσκου &εκτυπωτή…" + +msgid "Set &icon…" +msgstr "Ορισμός &εικονιδίου…" + +msgid "Select an icon" +msgstr "Επιλέξτε εικονίδιο" + +msgid "C&lone…" +msgstr "&Κλωνοποίηση…" + +msgid "Virtual machine \"%1\" (%2) will be cloned into:" +msgstr "Η εικονική μηχανή \"%1\" (%2) θα κλωνοποιηθεί σε:" + +msgid "Directory %1 already exists" +msgstr "Ο κατάλογος %1 υπάρχει ήδη" + +msgid "You cannot use the following characters in the name: %1" +msgstr "Δεν μπορείτε να χρησιμοποιήσετε τους ακόλουθους χαρακτήρες στο όνομα: %1" + +msgid "Clone" +msgstr "Κλωνοποίηση" + +msgid "Failed to create directory for cloned VM" +msgstr "Αποτυχία δημιουργίας καταλόγου για την κλωνοποιημένη VM" + +msgid "Failed to clone VM." +msgstr "Αποτυχία κλωνοποίησης VM." + +msgid "Directory in use" +msgstr "Κατάλογος σε χρήση" + +msgid "The selected directory is already in use. Please select a different directory." +msgstr "Ο επιλεγμένος κατάλογος χρησιμοποείται ήδη. Παρακαλώ επιλέξτε έναν διαφορετικό κατάλογο." + +msgid "Create directory failed" +msgstr "Αποτυχία δημιουργίας καταλόγου" + +msgid "Unable to create the directory for the new system" +msgstr "Αποτυχία δημιουργίας καταλόγου για το νέο σύστημα" + +msgid "Configuration write failed" +msgstr "Αποτυχία εγγραφής προσαρμογής" + +msgid "Unable to open the configuration file at %1 for writing" +msgstr "Αδυναμία ανοίγματος αρχείου προσαρμογής στο %1 για εγγραφή" + +msgid "Error adding system" +msgstr "Σφάλμα προσθήκης συστήματος" + +msgid "Remove directory failed" +msgstr "Αποτυχία αφαίρεσης καταλόγου" + +msgid "Some files in the machine's directory were unable to be deleted. Please delete them manually." +msgstr "Ορισμένα αρχεία στον κατάλογο μηχανής ήταν αδύνατο να διαγραφούν. Παρακαλώ διαγράψτε τα χειροκίνητα." + +msgid "Build" +msgstr "Δομή" + +msgid "Version" +msgstr "Έκδοση" + +msgid "An update to 86Box is available: %1 %2" +msgstr "Μία ενημέρωση είναι διαθέσιμη για το 86Box: %1 %2" + +msgid "An error has occurred while checking for updates: %1" +msgstr "Προέκυψε σφάλμα κατά τον έλεγχο ενημερώσεων: %1" + +msgid "An update to 86Box is available!" +msgstr "Μία ενημέρωση είναι διαθέσιμη για το 86Box!" + +msgid "Warning" +msgstr "Προειδοποίση" + +msgid "&Kill" +msgstr "&Εξαναγκαστικός τέρματισμός" + +msgid "Killing a virtual machine can cause data loss. Only do this if the 86Box process gets stuck.\n\nDo you really wish to kill the virtual machine \"%1\"?" +msgstr "Ο εξαναγκαστικός τέρματισμός της εικονικής μηχανής μπορεί να επιφέρει απώλεια δεδομένων. Εκτελέστε τον μόνο αν το 86Box εχει κολλήσει.\n\nΘέλετε οποσήποτε να κάνετε εξαναγκαστικό τέρματισμό της εικονικής μηχανής \"%1\";" + +msgid "&Delete" +msgstr "&Διαγραφή" + +msgid "Do you really want to delete the virtual machine \"%1\" and all its files? This action cannot be undone!" +msgstr "" +"Επιθυμείτε σίγουρα να διαγράψετε την εικονική μηχανή \"%1\" και όλα τα " +"αρχεία της; Αυτή η ενέργεια είναι ανεπανόρθωτη!" + +msgid "Show &config file" +msgstr "Εμφάνιση αρχείου &προσαρμογής" + +msgid "No screenshot" +msgstr "Κανένα στιγμιότυπο" + +msgid "Search" +msgstr "Αναζήτηση" + +msgid "Searching for VMs…" +msgstr "Αναζήτηση για VMs…" + +msgid "Found %1" +msgstr "Βρέθηκε %1" + +msgid "System" +msgstr "Σύστημα" + +msgid "Storage" +msgstr "Αποθηκευτικός χώρος" + +msgid "Disk %1:" +msgstr "Δισκέτα %1:" + +msgid "No disks" +msgstr "Κανένας δίσκος" + +msgid "Audio" +msgstr "Ήχος" + +msgid "Audio:" +msgstr "Ήχος:" + +msgid "ACPI shutdown" +msgstr "Τερματισμός ACPI" + +msgid "ACP&I shutdown" +msgstr "Τερματισμός ACP&I" + +msgid "Hard disk (%1)" +msgstr "Σκληρός δίσκος (%1)" + +msgid "MFM/RLL or ESDI CD-ROM drives never existed" +msgstr "Δεν υπήρξαν ποτέ οδηγοί MFM/RLL ή ESDI CD-ROM" + +msgid "Custom…" +msgstr "Προσαρμογή…" + +msgid "Custom (large)…" +msgstr "Προσαρμογή (μεγάλο)…" + +msgid "Add New Hard Disk" +msgstr "Προσθήκη Νέου Σκληρού Δίσκου" + +msgid "Add Existing Hard Disk" +msgstr "Προσθήκη Υπάρχων Σκληρού Δίσκου" + +msgid "HDI disk images cannot be larger than 4 GB." +msgstr "Οι εικόνες δίσκου HDI δεν μπορούν να είναι μεγαλύτερες απο 4 GB." + +msgid "Disk images cannot be larger than 127 GB." +msgstr "Οι εικόνες δίσκου δεν μπορούν να είναι μεγαλύτερες απο 127 GB." + +msgid "Hard disk images" +msgstr "Εικόνες σκληρού δίσκου" + +msgid "Unable to read file" +msgstr "Αδυναμία ανάγνωσης αρχείου" + +msgid "Unable to write file" +msgstr "Αδυναμία εγγραφής αρχείου" + +msgid "HDI or HDX images with a sector size other than 512 are not supported." +msgstr "Δεν υποστηρίζονται εικόνες HDI ή HDX με μέγεθος sector διαφορετικό από 512." + +msgid "Disk image file already exists" +msgstr "Το αρχείο εικόνας δίσκου υπάρχει ήδη" + +msgid "Please specify a valid file name." +msgstr "Παρακαλώ ορίστε άνα έγκυρο όνομα αρχείου." + +msgid "Disk image created" +msgstr "Η εικόνα δίσκου δημιουργήθηκε" + +msgid "Make sure the file exists and is readable." +msgstr "Βεβαιωθείτε οτι το αρχείο υπάρχει και οτι είναι αναγνώσιμο." + +msgid "Make sure the file is being saved to a writable directory." +msgstr "Βεβαιωθείτε οτι το αρχείο αποθηκεύεται σε έναν εγγράψιμο κατάλογο." + +msgid "Disk image too large" +msgstr "Η εικόνα δίσκου είναι αρκετά μεγάλη" + +msgid "Remember to partition and format the newly-created drive." +msgstr "Μην ξεχάσετε να κάνετε partition και format τον νέο-δημιουργημένο δίσκο." + +msgid "The selected file will be overwritten. Are you sure you want to use it?" +msgstr "Το επιλεγμένο αρχείο θα επανεγγραφεί. Θέλετε σίγουρα να το χρησιμοποιήσετε;" + +msgid "Unsupported disk image" +msgstr "Μη υποστηριζόμενη εικόνα δίσκου" + +msgid "Overwrite" +msgstr "Επανεγγραφή" + +msgid "Don't overwrite" +msgstr "Να μην γίνει επανεγγραφή" + +msgid "Raw image" +msgstr "Εικόνα Raw" + +msgid "HDI image" +msgstr "Εικόνα HDI" + +msgid "HDX image" +msgstr "Εικόνα HDX" + +msgid "Fixed-size VHD" +msgstr "Fixed-size VHD" + +msgid "Dynamic-size VHD" +msgstr "Dynamic-size VHD" + +msgid "Differencing VHD" +msgstr "Differencing VHD" + +msgid "(N/A)" +msgstr "(Μ/Δ)" + +msgid "Raw image (.img)" +msgstr "Εικόνα Raw (.img)" + +msgid "HDI image (.hdi)" +msgstr "Εικόνα HDI (.hdi)" + +msgid "HDX image (.hdx)" +msgstr "Εικόνα HDX (.hdx)" + +msgid "Fixed-size VHD (.vhd)" +msgstr "Fixed-size VHD (.vhd)" + +msgid "Dynamic-size VHD (.vhd)" +msgstr "Dynamic-size VHD (.vhd)" + +msgid "Differencing VHD (.vhd)" +msgstr "Differencing VHD (.vhd)" + +msgid "Large blocks (2 MB)" +msgstr "Large blocks (2 MB)" + +msgid "Small blocks (512 KB)" +msgstr "Small blocks (512 KB)" + +msgid "VHD files" +msgstr "Αρχεία VHD" + +msgid "Select the parent VHD" +msgstr "Επιλέξτε το αρχικό VHD" + +msgid "This could mean that the parent image was modified after the differencing image was created.\n\nIt can also happen if the image files were moved or copied, or by a bug in the program that created this disk.\n\nDo you want to fix the timestamps?" +msgstr "Αυτό μπορεί να σημαίνει οτι η αρχική εικόνα έχει τροποποιηθεί μετά την δημιουργία differencing image.\n\nΜπορεί επίσης να συμβεί αν τα αρχεία εικόνας έχουν μετακινηθεί ή αντιγραφεί, ή ένα bug του προγράμματος που δημιουργήθηκε αυτός ο δίσκος.\n\nΕπιθυμείτε να διορθώσετε τις χρονικές σημάνσεις;" + +msgid "Parent and child disk timestamps do not match" +msgstr "Οι χρονικές σημάνσεις αρχικού και δευτερεύον δίσκου δεν ταιριάζουν" + +msgid "Could not fix VHD timestamp." +msgstr "Αποτυχία διόρθωσης χρονικής σημάνσης VHD." + +msgid "CD-ROM %1 (%2): %3" +msgstr "CD-ROM %1 (%2): %3" + +msgid "&CD-ROM %1 (%2): %3" +msgstr "&CD-ROM %1 (%2): %3" + +msgid "160 KB" +msgstr "160 KB" + +msgid "180 KB" +msgstr "180 KB" + +msgid "320 KB" +msgstr "320 KB" + +msgid "360 KB" +msgstr "360 KB" + +msgid "640 KB" +msgstr "640 KB" + +msgid "720 KB" +msgstr "720 KB" + +msgid "1.2 MB" +msgstr "1.2 MB" + +msgid "1.25 MB" +msgstr "1.25 MB" + +msgid "1.44 MB" +msgstr "1.44 MB" + +msgid "DMF (cluster 1024)" +msgstr "DMF (cluster 1024)" + +msgid "DMF (cluster 2048)" +msgstr "DMF (cluster 2048)" + +msgid "2.88 MB" +msgstr "2.88 MB" + +msgid "ZIP 100" +msgstr "ZIP 100" + +msgid "3.5\" 128 MB (ISO 10090)" +msgstr "3.5\" 128 MB (ISO 10090)" + +msgid "3.5\" 230 MB (ISO 13963)" +msgstr "3.5\" 230 MB (ISO 13963)" + +msgid "3.5\" 540 MB (ISO 15498)" +msgstr "3.5\" 540 MB (ISO 15498)" + +msgid "3.5\" 640 MB (ISO 15498)" +msgstr "3.5\" 640 MB (ISO 15498)" + +msgid "3.5\" 1.3 GB (GigaMO)" +msgstr "3.5\" 1.3 GB (GigaMO)" + +msgid "3.5\" 2.3 GB (GigaMO 2)" +msgstr "3.5\" 2.3 GB (GigaMO 2)" + +msgid "5.25\" 600 MB" +msgstr "5.25\" 600 MB" + +msgid "5.25\" 650 MB" +msgstr "5.25\" 650 MB" + +msgid "5.25\" 1 GB" +msgstr "5.25\" 1 GB" + +msgid "5.25\" 1.3 GB" +msgstr "5.25\" 1.3 GB" + +msgid "Perfect RPM" +msgstr "Ιδανικό RPM" + +msgid "1% below perfect RPM" +msgstr "1% κάτω απο το ιδανικό RPM" + +msgid "1.5% below perfect RPM" +msgstr "1.5% κάτω απο το ιδανικό RPM" + +msgid "2% below perfect RPM" +msgstr "2% κάτω απο το ιδανικό RPM" + +msgid "(System Default)" +msgstr "(Προεπιλογή Συστήματος)" + +msgid "Failed to initialize network driver" +msgstr "Αποτυχία αρχικοποίησης οδηγού δικτύου" + +msgid "The network configuration will be switched to the null driver" +msgstr "Η παραμετροποίηση δικτύου θα αλλάξει σε άκυρο οδηγό" + +msgid "Mouse sensitivity:" +msgstr "Ευαισθησία ποντικιού:" + +msgid "Select media images from program working directory" +msgstr "Επιλέξτε αρχεία πολυμέσων απο τον ενεργό κατάλογο προγράμματος" + +msgid "PIT mode:" +msgstr "Λειτουργία PIT:" + +msgid "Auto" +msgstr "Αυτόματο" + +msgid "Slow" +msgstr "Αργό" + +msgid "Fast" +msgstr "Γρήγορο" + +msgid "&Auto-pause on focus loss" +msgstr "&Αυτόματο-πάγωμα σε απώλεια εστίασης" + +msgid "WinBox is no longer supported" +msgstr "Το WinBox δεν υποστηρίζεται πλέον" + +msgid "Development of the WinBox manager stopped in 2022 due to a lack of maintainers. As we direct our efforts towards making 86Box even better, we have made the decision to no longer support WinBox as a manager.\n\nNo further updates will be provided through WinBox, and you may encounter incorrect behavior should you continue using it with newer versions of 86Box. Any bug reports related to WinBox behavior will be closed as invalid.\n\nGo to 86box.net for a list of other managers you can use." +msgstr "" +"Η ανάπτυξη του WinBox σταμάτησε το 2022 λόγω έλλειψης maintainers. Καθώς " +"καταβάλλουμε κάθε δυνατή προσπάθεια για να βελτιώσουμε ακόμη περισσότερο το " +"86Box, έχουμε λάβει την απόφαση να μην υποστηρίζουμε πλέον το WinBox ως " +"διαχειριστή μηχανών.\n" +"\n" +"Δεν θα παρέχονται περαιτέρω ενημερώσεις μέσω του WinBox και ενδέχεται να " +"αντιμετωπίσετε εσφαλμένη συμπεριφορά σε περίπτωση που συνεχίσετε να το " +"χρησιμοποιείτε με νεότερες εκδόσεις του 86Box. Οποιεσδήποτε αναφορές " +"σφαλμάτων που σχετίζονται με τη συμπεριφορά του WinBox θα κλείνουν ως άκυρες." +"\n" +"\n" +"Μεταβείτε στο 86box.net για την λίστα με τους διαχειριστές μηχανών που " +"μπορείτε να χρησιμοποιήσετε." + +msgid "Generate" +msgstr "Δημιουργία" + +msgid "Joystick configuration" +msgstr "Ρύθμιση Joystick" + +msgid "Device" +msgstr "Συσκευή" + +msgid "%1 (X axis)" +msgstr "%1 (άξονας X)" + +msgid "%1 (Y axis)" +msgstr "%1 (άξονας Y)" + +msgid "MCA devices" +msgstr "Συσκευές MCA" + +msgid "List of MCA devices:" +msgstr "Λίστα συσκευών MCA:" + +msgid "&Tablet tool" +msgstr "Εργαλείο &Tablet" + +msgid "About &Qt" +msgstr "Σχετικά με το &Qt" + +msgid "&MCA devices…" +msgstr "Συσκευές &MCA…" + +msgid "Show non-&primary monitors" +msgstr "Εμφάνιση μη-&κύριων οθονών" + +msgid "Open screenshots &folder…" +msgstr "Άνοιγμα &φακέλου στιγμιότυπων…" + +msgid "Appl&y fullscreen stretch mode when maximized" +msgstr "&Εφαρμογή πλήρους οθόνης σε τέντωμα κατα την μεγιστοποίηση" + +msgid "&Cursor/Puck" +msgstr "&Cursor/Puck" + +msgid "&Pen" +msgstr "&Γραφίδα" + +msgid "&Host CD/DVD Drive (%1:)" +msgstr "&Host CD/DVD Drive (%1:)" + +msgid "&Connected" +msgstr "&Συνδεδεμένο" + +msgid "Clear image &history" +msgstr "Καθαρισμός &ιστορικού εικόνων" + +msgid "Create…" +msgstr "Δημιουργία…" + +msgid "Host CD/DVD Drive (%1)" +msgstr "Host CD/DVD Drive (%1)" + +msgid "Unknown Bus" +msgstr "Άγνωστος δίαυλος" + +msgid "Null Driver" +msgstr "Κενός Οδηγός" + +msgid "NIC:" +msgstr "NIC:" + +msgid "NIC %1 (%2) %3" +msgstr "NIC %1 (%2) %3" + +msgid "&NIC %1 (%2) %3" +msgstr "&NIC %1 (%2) %3" + +msgid "Render behavior" +msgstr "Συμπεριφορά απεικόνισης" + +msgid "Use target framerate:" +msgstr "Χρήση στόχου καρέ:" + +msgid " fps" +msgstr " fps" + +msgid "VSync" +msgstr "VSync" + +msgid "Synchronize with video" +msgstr "Συγχρονισμός με βίντεο" + +msgid "Shaders" +msgstr "Shaders" + +msgid "Remove" +msgstr "Κατάργηση" + +msgid "Browse…" +msgstr "Αναζήτηση…" + +msgid "Couldn't create OpenGL context." +msgstr "Αδυναμία δημιουργίας περιεχομένου OpenGL." + +msgid "Couldn't switch to OpenGL context." +msgstr "Αδυναμία εναλλαγής σε περιεχόμενο OpenGL." + +msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" +msgstr "Απαιτείται έκδοση OpenGL 3.0 ή νεότερη. Η τρέχουσα έκδοση είναι %1.%2" + +msgid "Error initializing OpenGL" +msgstr "Σφάλμα αρχικοποίησης OpenGL" + +msgid "\nFalling back to software rendering." +msgstr "" +"\n" +"Εναλλαγή σε απεικόνιση λογισμικού." + +msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgstr "" +"

Όταν επιλέγετε εικόνες πολυμέσων (CD-ROM, δισκέτα κλπ.)" +", το παράθυρο διαλόγου ανοίγματος θα ξεκινήσει στον ίδιο κατάλογο με το " +"αρχείο διαμόρφωσης του 86Box. Αυτή η ρύθμιση πιθανότατα θα κάνει τη διαφορά " +"μόνο σε macOS.

" + +msgid "This machine might have been moved or copied." +msgstr "Αυτή η μηχανή ίσως έχει μετακινηθεί ή αντιγραφεί." + +msgid "In order to ensure proper networking functionality, 86Box needs to know if this machine was moved or copied.\n\nSelect \"I Copied It\" if you are not sure." +msgstr "" +"Για να διασφαλιστεί η σωστή λειτουργία δικτύου, το 86Box πρέπει να γνωρίζει " +"αν αυτή η μηχανή έχει μετακινηθεί ή αντιγραφεί.\n" +"\n" +"Επιλέξτε \"Αντιγράφηκε\" εάν δεν είστε σίγουρος." + +msgid "I Moved It" +msgstr "Μετακινήθηκε" + +msgid "I Copied It" +msgstr "Αντιγράφηκε" + +msgid "86Box Monitor #%1" +msgstr "Οθόνη 86Box #%1" + +msgid "No MCA devices." +msgstr "Καμία συσκευή MCA." + +msgid "MiB" +msgstr "MiB" + +msgid "GiB" +msgstr "GiB" + +msgid "Network Card #1" +msgstr "Κάρτα δικτύου #1" + +msgid "Network Card #2" +msgstr "Κάρτα δικτύου #2" + +msgid "Network Card #3" +msgstr "Κάρτα δικτύου #3" + +msgid "Network Card #4" +msgstr "Κάρτα δικτύου #4" + +msgid "Mode:" +msgstr "Λειτουργία:" + +msgid "Interface:" +msgstr "Διασύνδεση:" + +msgid "Adapter:" +msgstr "Προσαρμογέας:" + +msgid "VDE Socket:" +msgstr "VDE Socket:" + +msgid "TAP Bridge Device:" +msgstr "Συσκευή TAP Γέφυρας:" + +msgid "86Box Unit Tester" +msgstr "Μονάδα δοκιμής 86Box" + +msgid "Novell NetWare 2.x Key Card" +msgstr "Novell NetWare 2.x Key Card" + +msgid "Serial port passthrough 1" +msgstr "Διέλευση σειριακής πόρτας 1" + +msgid "Serial port passthrough 2" +msgstr "Διέλευση σειριακής πόρτας 2" + +msgid "Serial port passthrough 3" +msgstr "Διέλευση σειριακής πόρτας 3" + +msgid "Serial port passthrough 4" +msgstr "Διέλευση σειριακής πόρτας 4" + +msgid "Renderer &options…" +msgstr "&Επιλογές απεικόνισης…" + +msgid "PC/XT Keyboard" +msgstr "Πληκτρολόγιο PC/XT" + +msgid "AT Keyboard" +msgstr "Πληκτρολόγιο AT" + +msgid "AX Keyboard" +msgstr "Πληκτρολόγιο AX" + +msgid "PS/2 Keyboard" +msgstr "Πληκτρολόγιο PS/2" + +msgid "PS/55 Keyboard" +msgstr "Πληκτρολόγιο PS/55" + +msgid "Keys" +msgstr "Πλήκτρα" + +msgid "Logitech/Microsoft Bus Mouse" +msgstr "Ποντίκι διαύλου Logitech/Microsoft" + +msgid "Microsoft Bus Mouse (InPort)" +msgstr "Ποντίκι διαύλου Microsoft (InPort)" + +msgid "Mouse Systems Serial Mouse" +msgstr "Σειριακό ποντίκι Mouse Systems" + +msgid "Mouse Systems Bus Mouse" +msgstr "Ποντίκι διαύλου Mouse Systems" + +msgid "Microsoft Serial Mouse" +msgstr "Σειριακό ποντίκι Microsoft" + +msgid "Microsoft Serial BallPoint" +msgstr "Σειριακό ποντίκι Microsoft BallPoint" + +msgid "Logitech Serial Mouse" +msgstr "Σειριακό ποντίκι Logitech" + +msgid "PS/2 Mouse" +msgstr "Ποντίκι PS/2" + +msgid "PS/2 QuickPort Mouse" +msgstr "Ποντίκι PS/2 QuickPort" + +msgid "3M MicroTouch (Serial)" +msgstr "3M MicroTouch (Σειριακό)" + +msgid "Default Baud rate" +msgstr "Προεπιλεγμένος ρυθμός Baud" + +msgid "Standard Hayes-compliant Modem" +msgstr "Τυπικό μόντεμ συμβατό με Hayes" + +msgid "Roland MT-32 Emulation" +msgstr "Εξομοίωση Roland MT-32" + +msgid "Roland MT-32 (New) Emulation" +msgstr "Εξομοίωση Roland MT-32 (Νέο)" + +msgid "Roland CM-32L Emulation" +msgstr "Εξομοίωση Roland CM-32L" + +msgid "Roland CM-32LN Emulation" +msgstr "Εξομοίωση Roland CM-32LN" + +msgid "OPL4-ML Daughterboard" +msgstr "Θυγατρική κάρτα OPL4-ML" + +msgid "System MIDI" +msgstr "MIDI συστήματος" + +msgid "MIDI Input Device" +msgstr "Συσκευή Εισαγωγής MIDI" + +msgid "BIOS file" +msgstr "Αρχείο BIOS" + +msgid "BIOS file (ROM #1)" +msgstr "Αρχείο BIOS (ROM #1)" + +msgid "BIOS file (ROM #2)" +msgstr "Αρχείο BIOS (ROM #2)" + +msgid "BIOS file (ROM #3)" +msgstr "Αρχείο BIOS (ROM #3)" + +msgid "BIOS file (ROM #4)" +msgstr "Αρχείο BIOS (ROM #4)" + +msgid "BIOS address" +msgstr "Διεύθυνση BIOS" + +msgid "BIOS address (ROM #1)" +msgstr "Διεύθυνση BIOS (ROM #1)" + +msgid "BIOS address (ROM #2)" +msgstr "Διεύθυνση BIOS (ROM #2)" + +msgid "BIOS address (ROM #3)" +msgstr "Διεύθυνση BIOS (ROM #3)" + +msgid "BIOS address (ROM #4)" +msgstr "Διεύθυνση BIOS (ROM #4)" + +msgid "Enable BIOS extension ROM Writes" +msgstr "Ενεργοποίηση επέκτασης BIOS εγγραφών ROM" + +msgid "Enable BIOS extension ROM Writes (ROM #1)" +msgstr "Ενεργοποίηση επέκτασης BIOS εγγραφών ROM (ROM #1)" + +msgid "Enable BIOS extension ROM Writes (ROM #2)" +msgstr "Ενεργοποίηση επέκτασης BIOS εγγραφών ROM (ROM #2)" + +msgid "Enable BIOS extension ROM Writes (ROM #3)" +msgstr "Ενεργοποίηση επέκτασης BIOS εγγραφών ROM (ROM #3)" + +msgid "Enable BIOS extension ROM Writes (ROM #4)" +msgstr "Ενεργοποίηση επέκτασης BIOS εγγραφών ROM (ROM #4)" + +msgid "Linear framebuffer base" +msgstr "Βάση γραμμικού framebuffer" + +msgid "Address" +msgstr "Διεύθυνση" + +msgid "IRQ" +msgstr "IRQ" + +msgid "Serial port IRQ" +msgstr "IRQ σειριακής θύρας" + +msgid "Parallel port IRQ" +msgstr "IRQ παράλληλης θύρας" + +msgid "Hard disk" +msgstr "Σκληρός δίσκος" + +msgid "BIOS Revision" +msgstr "Αναθεώρηση BIOS" + +msgid "BIOS Version" +msgstr "Έκδοση BIOS" + +msgid "BIOS Language" +msgstr "Γλώσσα BIOS" + +msgid "IBM 5161 Expansion Unit" +msgstr "Επέκταση μονάδας IBM 5161" + +msgid "IBM Cassette Basic" +msgstr "IBM Cassette Basic" + +msgid "Translate 26 -> 17" +msgstr "Μετάφρασε 26 -> 17" + +msgid "Language" +msgstr "Γλώσσα" + +msgid "Enable backlight" +msgstr "Ενεργοποίηση οπίσθιου φωτισμού" + +msgid "Invert colors" +msgstr "Αντιστροφή χρωμάτων" + +msgid "BIOS size" +msgstr "Μέγεθος BIOS" + +msgid "BIOS size (ROM #1)" +msgstr "Μέγεθος BIOS (ROM #1)" + +msgid "BIOS size (ROM #2)" +msgstr "Μέγεθος BIOS (ROM #2)" + +msgid "BIOS size (ROM #3)" +msgstr "Μέγεθος BIOS (ROM #3)" + +msgid "BIOS size (ROM #4)" +msgstr "Μέγεθος BIOS (ROM #4)" + +msgid "Map C0000-C7FFF as UMB" +msgstr "Ορισμός C0000-C7FFF ως UMB" + +msgid "Map C8000-CFFFF as UMB" +msgstr "Ορισμός C8000-CFFFF ως UMB" + +msgid "Map D0000-D7FFF as UMB" +msgstr "Ορισμός D0000-D7FFF ως UMB" + +msgid "Map D8000-DFFFF as UMB" +msgstr "Ορισμός D8000-DFFFF ως UMB" + +msgid "Map E0000-E7FFF as UMB" +msgstr "Ορισμός E0000-E7FFF ως UMB" + +msgid "Map E8000-EFFFF as UMB" +msgstr "Ορισμός E8000-EFFFF ως UMB" + +msgid "JS9 Jumper (JIM)" +msgstr "JS9 Jumper (JIM)" + +msgid "MIDI Output Device" +msgstr "Συσκευή Εξόδου MIDI" + +msgid "MIDI Real time" +msgstr "MIDI Πραγματικού χρόνου" + +msgid "MIDI Thru" +msgstr "MIDI Thru" + +msgid "MIDI Clockout" +msgstr "MIDI Clockout" + +msgid "Output Gain" +msgstr "Ενίσχυση Έντασης" + +msgid "Chorus" +msgstr "Chorus" + +msgid "Chorus Voices" +msgstr "Chorus Voices" + +msgid "Chorus Level" +msgstr "Επίπεδο Chorus" + +msgid "Chorus Speed" +msgstr "Ταχύτητα Chorus" + +msgid "Chorus Depth" +msgstr "Βάθος Chorus" + +msgid "Chorus Waveform" +msgstr "Chorus Waveform" + +msgid "Reverb" +msgstr "Reverb" + +msgid "Reverb Room Size" +msgstr "Μέγεθος Δωματίου Reverb" + +msgid "Reverb Damping" +msgstr "Απόσβεση Reverb" + +msgid "Reverb Width" +msgstr "Πλάτος Reverb" + +msgid "Reverb Level" +msgstr "Επίπεδο Reverb" + +msgid "Interpolation Method" +msgstr "Μέθοδος παρεμβολής" + +msgid "Dynamic Sample Loading" +msgstr "Φόρτωση Δυναμικού Δείγματος" + +msgid "Reverb Output Gain" +msgstr "Ενίσχυση Εξόδου Reverb" + +msgid "Reversed stereo" +msgstr "Αντίστροφο Στέρεο" + +msgid "Nice ramp" +msgstr "Ωραία ράμπα" + +msgid "Hz" +msgstr "Hz" + +msgid "Buttons" +msgstr "Κουμπιά" + +msgid "Serial Port" +msgstr "Σειριακή θύρα" + +msgid "RTS toggle" +msgstr "RTS toggle" + +msgid "Revision" +msgstr "Αναθεώρηση" + +msgid "Controller" +msgstr "Controller" + +msgid "Show Crosshair" +msgstr "Εμφάνιση στόχαστρου" + +msgid "DMA" +msgstr "DMA" + +msgid "MAC Address" +msgstr "Διεύθυνση MAC" + +msgid "MAC Address OUI" +msgstr "Διεύθυνση MAC OUI" + +msgid "Enable BIOS" +msgstr "Ενεργοποίηση BIOS" + +msgid "Baud Rate" +msgstr "Τιμή Baud" + +msgid "TCP/IP listening port" +msgstr "Θύρα ακρόασης TCP/IP" + +msgid "Phonebook File" +msgstr "Αρχείο Τηλεφωνικού καταλόγου" + +msgid "Telnet emulation" +msgstr "Εξομοίωση Telnet" + +msgid "RAM Address" +msgstr "Διεύθυνση RAM" + +msgid "RAM size" +msgstr "Μέγεθος RAM" + +msgid "Initial RAM size" +msgstr "Αρχικό μέγεθος RAM" + +msgid "Serial Number" +msgstr "Σειριακός Αριθμός" + +msgid "Host ID" +msgstr "ID οικοδεσπότη" + +msgid "FDC Address" +msgstr "Διεύθυνση FDC" + +msgid "MPU-401 Address" +msgstr "Διεύθυνση MPU-401" + +msgid "MPU-401 IRQ" +msgstr "MPU-401 IRQ" + +msgid "Receive MIDI input" +msgstr "Λήψη εισαγωγής MIDI" + +msgid "Low DMA" +msgstr "Χαμηλό DMA" + +msgid "Enable Game port" +msgstr "Ενεργοποίηση Game port" + +msgid "Enable Adlib ports" +msgstr "Ενεργοποίηση θυρών Adlib" + +msgid "SID Model" +msgstr "Μοντέλο SID" + +msgid "SID Filter Strength" +msgstr "Ισχύς Φίλτρου SID" + +msgid "Surround module" +msgstr "Μονάδα Surround" + +msgid "SB Address" +msgstr "Διεύθυνση SB" + +msgid "Adlib Address" +msgstr "Διεύθυνση Adlib" + +msgid "Use EEPROM setting" +msgstr "Χρήση ρύθμισης EEPROM" + +msgid "WSS IRQ" +msgstr "WSS IRQ" + +msgid "WSS DMA" +msgstr "WSS DMA" + +msgid "RTC IRQ" +msgstr "RTC IRQ" + +msgid "RTC Port Address" +msgstr "Διεύθυνση Θύρας RTC" + +msgid "Onboard RTC" +msgstr "Ενσωματωμένο RTC" + +msgid "Not installed" +msgstr "Μη εγκατεστημένο" + +msgid "Enable OPL" +msgstr "Ενεργοποίηση OPL" + +msgid "Receive MIDI input (MPU-401)" +msgstr "Λήψη εισαγωγής MIDI (MPU-401)" + +msgid "SB low DMA" +msgstr "χαμηλό DMA της SB" + +msgid "6CH variant (6-channel)" +msgstr "Παραλλαγή 6CH (6-κάναλο)" + +msgid "Enable CMS" +msgstr "Ενεργοποίηση CMS" + +msgid "Mixer" +msgstr "Μίκτης" + +msgid "High DMA" +msgstr "Υψηλό DMA" + +msgid "Control PC speaker" +msgstr "Έλεγχος ηχείου PC" + +msgid "Memory size" +msgstr "Μέγεθος μνήμης" + +msgid "EMU8000 Address" +msgstr "Διεύθυνση EMU8000" + +msgid "IDE Controller" +msgstr "Ελεγκτής IDE" + +msgid "Codec" +msgstr "Codec" + +msgid "GUS type" +msgstr "Τύπος GUS" + +msgid "Enable 0x04 \"Exit 86Box\" command" +msgstr "Ενεργοποίηση εντολής 0x04 \"Έξοδος 86Box\"" + +msgid "Display type" +msgstr "Τύπος εμφάνισης" + +msgid "Composite type" +msgstr "Τύπος Composite" + +msgid "RGB type" +msgstr "Τύπος RGB" + +msgid "Line doubling type" +msgstr "Τύπος line doubling" + +msgid "Snow emulation" +msgstr "Εξομοίωση εφέ \"χιονιού\"" + +msgid "Monitor type" +msgstr "Τύπος οθόνης" + +msgid "Character set" +msgstr "Σετ χαρακτήρων" + +msgid "XGA type" +msgstr "Τύπος XGA" + +msgid "Instance" +msgstr "Παράδειγμα" + +msgid "MMIO Address" +msgstr "Διεύθυνση MMIO" + +msgid "RAMDAC type" +msgstr "Τύπος RAMDAC" + +msgid "Blend" +msgstr "Ανάμιξη" + +msgid "Font" +msgstr "Γραμματοσειρά" + +msgid "Bilinear filtering" +msgstr "Διγραμμικό φίλτρο" + +msgid "Video chroma-keying" +msgstr "Video chroma-keying" + +msgid "Dithering" +msgstr "Χρωματική αντιπαράθεση" + +msgid "Enable NMI for CGA emulation" +msgstr "Ενεργοποίηση NMI για εξομοίωση CGA" + +msgid "Voodoo type" +msgstr "Τύπος Voodoo" + +msgid "Framebuffer memory size" +msgstr "Μέγεθος μνήμης Framebuffer" + +msgid "Texture memory size" +msgstr "Μέγεθος μνήμης υφών" + +msgid "Dither subtraction" +msgstr "Αφαίρεση τρέμουλου" + +msgid "Screen Filter" +msgstr "Φίλτρο οθόνης" + +msgid "Render threads" +msgstr "Νήματα απεικονιστή" + +msgid "SLI" +msgstr "SLI" + +msgid "Start Address" +msgstr "Διεύθυνση εκκίνησης" + +msgid "Contiguous Size" +msgstr "Μέγεθος συνέχειας" + +msgid "I/O Width" +msgstr "Πλάτος I/O" + +msgid "Transfer Speed" +msgstr "Ταχύτητα Μεταφοράς" + +msgid "EMS mode" +msgstr "Λειτουργία EMS" + +msgid "EMS Address" +msgstr "Διεύθυνση EMS" + +msgid "EMS 1 Address" +msgstr "Διεύθυνση EMS 1" + +msgid "EMS 2 Address" +msgstr "Διεύθυνση EMS 2" + +msgid "EMS Memory Size" +msgstr "Μέγεθος μνήμης EMS" + +msgid "EMS 1 Memory Size" +msgstr "Μέγεθος μνήμης EMS 1" + +msgid "EMS 2 Memory Size" +msgstr "Μέγεθος μνήμης EMS 2" + +msgid "Enable EMS" +msgstr "Ενεργοποίηση EMS" + +msgid "Enable EMS 1" +msgstr "Ενεργοποίηση EMS 1" + +msgid "Enable EMS 2" +msgstr "Ενεργοποίηση EMS 2" + +msgid "Address for > 2 MB" +msgstr "Διεύθυνση για > 2 MB" + +msgid "Frame Address" +msgstr "Διεύθυνση πλαισίου" + +msgid "USA" +msgstr "ΗΠΑ" + +msgid "Danish" +msgstr "Δανικά" + +msgid "Always at selected speed" +msgstr "Πάντα στην επιλεγμένη ταχύτητα" + +msgid "BIOS setting + Hotkeys (off during POST)" +msgstr "Ρύθμιση BIOS + Συντόμευση πλήκτρων (ανενεργά κατά το POST)" + +msgid "64 KB starting from F0000" +msgstr "64 KB αρχή από F0000" + +msgid "128 KB starting from E0000 (address MSB inverted, last 64 KB first)" +msgstr "" +"128 KB αρχή από E0000 (διεύθυνση MSB αντεστραμμένη, τελευταία 64 KB πρώτα)" + +msgid "Sine" +msgstr "Ημίτονο" + +msgid "Triangle" +msgstr "Τρίγωνο" + +msgid "Linear" +msgstr "Γραμμικό" + +msgid "4th Order" +msgstr "4η Τάξη" + +msgid "7th Order" +msgstr "7η Τάξη" + +msgid "Non-timed (original)" +msgstr "Χωρίς χρονικό περιορισμό (πρωτότυπο)" + +msgid "45 Hz (JMP2 not populated)" +msgstr "45 Hz (JMP2 not populated)" + +msgid "Two" +msgstr "Δύο" + +msgid "Three" +msgstr "Τρία" + +msgid "Wheel" +msgstr "Τροχό" + +msgid "Five + Wheel" +msgstr "Πέντε + Τροχό" + +msgid "Five + 2 Wheels" +msgstr "Πέντε + 2 Τροχοί" + +msgid "A3 - SMT2 Serial / SMT3(R)V" +msgstr "A3 - SMT2 Serial / SMT3(R)V" + +msgid "Q1 - SMT3(R) Serial" +msgstr "Q1 - SMT3(R) Serial" + +msgid "8 KB" +msgstr "8 KB" + +msgid "32 KB" +msgstr "32 KB" + +msgid "16 KB" +msgstr "16 KB" + +msgid "64 KB" +msgstr "64 KB" + +msgid "Disable BIOS" +msgstr "Απενεργοποίηση BIOS" + +msgid "512 KB" +msgstr "512 KB" + +msgid "2 MB" +msgstr "2 MB" + +msgid "8 MB" +msgstr "8 MB" + +msgid "28 MB" +msgstr "28 MB" + +msgid "1 MB" +msgstr "1 MB" + +msgid "4 MB" +msgstr "4 MB" + +msgid "12 MB" +msgstr "12 MB" + +msgid "16 MB" +msgstr "16 MB" + +msgid "20 MB" +msgstr "20 MB" + +msgid "24 MB" +msgstr "24 MB" + +msgid "SigmaTel STAC9721T (stereo)" +msgstr "SigmaTel STAC9721T (stereo)" + +msgid "256 KB" +msgstr "256 KB" + +msgid "Composite" +msgstr "Composite" + +msgid "True color" +msgstr "Ζωντανά χρώματα" + +msgid "Old" +msgstr "Παλαιό" + +msgid "New" +msgstr "Νέο" + +msgid "Color (generic)" +msgstr "Έγχρωμο (γενικό)" + +msgid "Green Monochrome" +msgstr "Μονόχρωμο Πράσινο" + +msgid "Amber Monochrome" +msgstr "Μονόχρωμο Κεχριμπάρι" + +msgid "Gray Monochrome" +msgstr "Μονόχρωμο Γκρι" + +msgid "Color (no brown)" +msgstr "Έγχρωμο (χωρίς το καφέ)" + +msgid "Color (IBM 5153)" +msgstr "Έγχρωμο (IBM 5153)" + +msgid "Simple doubling" +msgstr "Απλός διπλασιασμός" + +msgid "sRGB interpolation" +msgstr "Παρεμβολή sRGB" + +msgid "Linear interpolation" +msgstr "Γραμμική παρεμβολή" + +msgid "Has secondary 8x8 character set" +msgstr "Έχει δευτερεύον σετ χαρακτήρων 8x8" + +msgid "Has Quadcolor II daughter board" +msgstr "Έχει θυγατρική πλακέτα Quadcolor II" + +msgid "Alternate monochrome contrast" +msgstr "Εναλλακτική μονόχρωμη αντίθεση" + +msgid "128 KB" +msgstr "128 KB" + +msgid "Monochrome (5151/MDA) (white)" +msgstr "Μονόχρωμο (5151/MDA) (λευκό)" + +msgid "Monochrome (5151/MDA) (green)" +msgstr "Μονόχρωμο (5151/MDA) πράσινο)" + +msgid "Monochrome (5151/MDA) (amber)" +msgstr "Μονόχρωμο (5151/MDA) (κεχριμπάρι)" + +msgid "Color 40x25 (5153/CGA)" +msgstr "Έγχρωμο 40x25 (5153/CGA)" + +msgid "Color 80x25 (5153/CGA)" +msgstr "Έγχρωμο 80x25 (5153/CGA)" + +msgid "Enhanced Color - Normal Mode (5154/ECD)" +msgstr "Ενισχυμένο Έγχρωμο - Κανονική Λειτουργία (5154/ECD)" + +msgid "Enhanced Color - Enhanced Mode (5154/ECD)" +msgstr "Ενισχυμένο Έγχρωμο - Ενισχυμένη Λειτουργία (5154/ECD)" + +msgid "Green" +msgstr "Πράσινο" + +msgid "Amber" +msgstr "Κεχριμπάρι" + +msgid "Gray" +msgstr "Γκρι" + +msgid "Grayscale" +msgstr "Κλίμακα του γκρι" + +msgid "Color" +msgstr "Έγχρωμο" + +msgid "U.S. English" +msgstr "Αγγλικά Η.Π." + +msgid "Scandinavian" +msgstr "Σκανδιναβικά" + +msgid "Other languages" +msgstr "Άλλες γλώσσες" + +msgid "Bochs latest" +msgstr "Τελευταία έκδοση Bochs" + +msgid "Apply overscan deltas" +msgstr "Εφαρμογή υπερσάρωσης δέλτα" + +msgid "Mono Interlaced" +msgstr "Μονόχρωμο πλεγμένο" + +msgid "Mono Non-Interlaced" +msgstr "Μονόχρωμο Μη-πλεγμένο" + +msgid "Color Interlaced" +msgstr "Έγχρωμο πλεγμένο" + +msgid "Color Non-Interlaced" +msgstr "Έγχρωμο Μη-πλεγμένο" + +msgid "3Dfx Voodoo Graphics" +msgstr "Γραφικά 3Dfx Voodoo" + +msgid "3Dfx Voodoo 2" +msgstr "3Dfx Voodoo 2" + +msgid "Obsidian SB50 + Amethyst (2 TMUs)" +msgstr "Obsidian SB50 + Amethyst (2 TMUs)" + +msgid "8-bit" +msgstr "8-bit" + +msgid "16-bit" +msgstr "16-bit" + +msgid "Standard (150ns)" +msgstr "Κανονικό (150ns)" + +msgid "High-Speed (120ns)" +msgstr "Υψηλής-Ταχύτητας (120ns)" + +msgid "Enabled" +msgstr "Ενεργοποιημένο" + +msgid "Standard" +msgstr "Κανονικό" + +msgid "High-Speed" +msgstr "Υψηλής-Ταχύτητας" + +msgid "Stereo LPT DAC" +msgstr "Στέρεο LPT DAC" + +msgid "Generic Text Printer" +msgstr "Γενικός Εκτυπωτής Κειμένου" + +msgid "Generic ESC/P 2 Dot-Matrix Printer" +msgstr "Γενικός Εκτυπωτής ESC/P 2 Dot-Matrix" + +msgid "Generic PostScript Printer" +msgstr "Γενικός Εκτυπωτής PostScript" + +msgid "Generic PCL5e Printer" +msgstr "Γενικός Εκτυπωτής PCL5e" + +msgid "Parallel Line Internet Protocol" +msgstr "Πρωτόκολλο Παράλληλης Γραμμής Internet" + +msgid "Protection Dongle for Savage Quest" +msgstr "Dongle προστασίας για το Savage Quest" + +msgid "Serial Passthrough Device" +msgstr "Συσκευή Σειριακής Διέλευσης" + +msgid "Passthrough Mode" +msgstr "Λειτουργία Διέλευσης" + +msgid "Host Serial Device" +msgstr "Σειριακή Συσκευή Οικοδεσπότη" + +msgid "Name of pipe" +msgstr "Όνομα pipe" + +msgid "Data bits" +msgstr "Bits δεδομένων" + +msgid "Stop bits" +msgstr "Bits σταματήματος" + +msgid "Baud Rate of Passthrough" +msgstr "Ρυθμός Baud της Διέλευσης" + +msgid "Named Pipe (Server)" +msgstr "Ονομασμένο Pipe (Διακομιστής)" + +msgid "Named Pipe (Client)" +msgstr "Ονομασμένο Pipe (Πελάτης)" + +msgid "Host Serial Passthrough" +msgstr "Σειριακή Διέλευση Οικοδεσπότη" + +msgid "E&ject %1" +msgstr "&Εξαγωγή %1" + +msgid "&Unmute" +msgstr "&Κατάργηση σίγασης" + +msgid "Softfloat FPU" +msgstr "FPU Softfloat" + +msgid "High performance impact" +msgstr "Μεγάλη επίπτωση στην απόδοση" + +msgid "[Generic] RAM Disk (max. speed)" +msgstr "[Γενικό] RAM Disk (τέρμα ταχύτητα)" + +msgid "[Generic] 1989 (3500 RPM)" +msgstr "[Γενικό] 1989 (3500 RPM)" + +msgid "[Generic] 1992 (3600 RPM)" +msgstr "[Γενικό] 1992 (3600 RPM)" + +msgid "[Generic] 1994 (4500 RPM)" +msgstr "[Γενικό] 1994 (4500 RPM)" + +msgid "[Generic] 1996 (5400 RPM)" +msgstr "[Γενικό] 1996 (5400 RPM)" + +msgid "[Generic] 1997 (5400 RPM)" +msgstr "[Γενικό] 1997 (5400 RPM)" + +msgid "[Generic] 1998 (5400 RPM)" +msgstr "[Γενικό] 1998 (5400 RPM)" + +msgid "[Generic] 2000 (7200 RPM)" +msgstr "[Γενικό] 2000 (7200 RPM)" + +msgid "IBM 8514/A clone (ISA)" +msgstr "Κλώνος IBM 8514/A (ISA)" + +msgid "Vendor" +msgstr "Πωλητής" + +msgid "30 Hz (JMP2 = 1)" +msgstr "30 Hz (JMP2 = 1)" + +msgid "60 Hz (JMP2 = 2)" +msgstr "60 Hz (JMP2 = 2)" + +msgid "Generic PC/XT Memory Expansion" +msgstr "Γενική Επέκταση Μνήμης PC/XT" + +msgid "Generic PC/AT Memory Expansion" +msgstr "Γενική Επέκταση Μνήμης PC/AT" + +msgid "Unable to find Dot-Matrix fonts" +msgstr "Αδυναμία εύρεσης γραμματοσειρών Dot-Matrix" + +msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P 2 Dot-Matrix Printer." +msgstr "" +"Απαιτούνται γραμματοσειρές TrueType στον κατάλογο \"roms/printer/fonts\" για " +"την εξομοίωση Γενικού εκτυπωτή ESC/P 2 Dot-Matrix." + +msgid "Inhibit multimedia keys" +msgstr "Αναστολή πλήκτρων πολυμέσων" + +msgid "Ask for confirmation before saving settings" +msgstr "Ερώτηση επιβεβαίωσης πριν από την αποθήκευση των ρυθμίσεων" + +msgid "Ask for confirmation before hard resetting" +msgstr "Ερώτηση επιβεβαίωσης πριν από την ολική επανεκκίνηση" + +msgid "Ask for confirmation before quitting" +msgstr "Ερώτηση επιβεβαίωσης κατά την έξοδο" + +msgid "Options" +msgstr "Επιλογές" + +msgid "Model" +msgstr "Μοντέλο" + +msgid "Model:" +msgstr "Μοντέλο:" + +msgid "Failed to initialize Vulkan renderer." +msgstr "Αποτυχία αρχικοποίησης απεικονιστή Vulkan." + +msgid "GLSL Error" +msgstr "Σφάλμα GLSL" + +msgid "Could not load shader: %1" +msgstr "Αδυναμία φόρτωσης σκίασης: %1" + +msgid "Could not load texture: %1" +msgstr "Αδυναμία φόρτωσης υφής: %1" + +msgid "Could not compile shader:\n\n%1" +msgstr "" +"Αδυναμία σύνταξης σκίασης:\n" +"\n" +"%1" + +msgid "Program not linked:\n\n%1" +msgstr "" +"Το πρόγραμμα δεν είναι συνδεδεμένο:\n" +"\n" +"%1" + +msgid "Shader Manager" +msgstr "Διαχειριστής Σκίασης" + +msgid "Shader Configuration" +msgstr "Διαμόρφωση Σκίασης" + +msgid "Add" +msgstr "Προσθήκη" + +msgid "Move up" +msgstr "Μετακίνηση επάνω" + +msgid "Move down" +msgstr "Μετακίνηση κάτω" + +msgid "Could not load file %1" +msgstr "Αδυναμία φόρτωσης αρχείου %1" + +msgid "Key Bindings:" +msgstr "Αντιστοιχίσεις Πλήκτρων:" + +msgid "Action" +msgstr "Ενέργεια" + +msgid "Keybind" +msgstr "Αντιστοιχία πλήκτρου" + +msgid "Clear binding" +msgstr "Καθαρισμός αντιστοιχίας" + +msgid "Bind" +msgstr "Αντιστοίχησε" + +msgid "Bind Key" +msgstr "Αντιστοίχησε Πλήκτρο" + +msgid "Enter key combo:" +msgstr "Εισαγωγή συνδυασμού πλήκτρων:" + +msgid "Bind conflict" +msgstr "Αντίκρουση αντιστοιχίας" + +msgid "This key combo is already in use." +msgstr "Αυτός ο συνδυασμός πλήκτρων χρησιμοποιείται ήδη." + +msgid "Send Control+Alt+Del" +msgstr "Αποστολή Control+Alt+Del" + +msgid "Send Control+Alt+Escape" +msgstr "Αποστολή Control+Alt+Escape" + +msgid "Toggle fullscreen" +msgstr "Εναλλαγή σε πλήρη οθόνη" + +msgid "Toggle UI in fullscreen" +msgstr "Εναλλαγή ΠΧ σε πλήρη οθόνη" + +msgid "Release mouse pointer" +msgstr "Απελευθέρωση δείκτη ποντικιού" + +msgid "Toggle pause" +msgstr "Εναλλαγή παύσης" + +msgid "Toggle mute" +msgstr "Εναλλαγή σίγασης" + +msgid "Text files" +msgstr "Αρχεία κειμένου" + +msgid "ROM files" +msgstr "Αρχεία ROM" + +msgid "SoundFont files" +msgstr "Αρχεία SoundFont" + +msgid "Local Switch" +msgstr "Τοπικός Διακόπτης" + +msgid "Remote Switch" +msgstr "Απομακρυσμένος Διακόπτης" + +msgid "Switch:" +msgstr "Διακόπτης:" + +msgid "Hub Mode" +msgstr "Λειτουργία Hub" + +msgid "Hostname:" +msgstr "Όνομα οικοδεσπότη:" + +msgid "ISA RAM:" +msgstr "ISA RAM:" + +msgid "ISA ROM:" +msgstr "ISA ROM:" + +msgid "&Wipe NVRAM" +msgstr "&Εκκαθάριση NVRAM" + +msgid "This will delete all NVRAM (and related) files of the virtual machine located in the \"nvr\" subdirectory. You'll have to reconfigure the BIOS (and possibly other devices inside the VM) settings again if applicable.\n\nAre you sure you want to wipe all NVRAM contents of the virtual machine \"%1\"?" +msgstr "" +"Αυτό θα διαγράψει όλα τα αρχεία NVRAM (και τα σχετικά) της εικονικής μηχανής " +"που βρίσκονται στον υποκατάλογο \"nvr\". Θα πρέπει να επαναρυθμίσετε το BIOS " +"(και πιθανώς άλλε συσκευές εντός της εικονικής μηχανής), εάν είναι " +"απαραίτητο.\n" +"\n" +"Είστε βέβαιοι ότι θέλετε να διαγράψετε όλα τα περιεχόμενα NVRAM της " +"εικονικής μηχανής \"%1\";" + +msgid "Success" +msgstr "Επιτυχία" + +msgid "Successfully wiped the NVRAM contents of the virtual machine \"%1\"" +msgstr "Επιτυχής διαγραφή των περιεχομένων NVRAM της εικονικής μηχανής \"%1\"" + +msgid "An error occurred trying to wipe the NVRAM contents of the virtual machine \"%1\"" +msgstr "" + +msgid "%1 VM Manager" +msgstr "" + +msgid "%n disk(s)" +msgstr "" + +msgid "Unknown Status" +msgstr "" + +msgid "No Machines Found!" +msgstr "" + +msgid "Check for updates on startup" +msgstr "Έλεγχος για ενημερώσεις κατα την εκκίνηση" + +msgid "Unable to determine release information" +msgstr "" + +msgid "There was an error checking for updates:\n\n%1\n\nPlease try again later." +msgstr "" +"Υπήρξε σφάλμα κατα τον έλεγχο για ενημερώσεις :\n" +"\n" +"%1\n" +"\n" +"Παρακαλώ προσπαθήστε ξανά αργότερα." + +msgid "Update check complete" +msgstr "" + +msgid "stable" +msgstr "" + +msgid "beta" +msgstr "" + +msgid "You are running the latest %1 version of 86Box: %2" +msgstr "" + +msgid "version" +msgstr "" + +msgid "build" +msgstr "" + +msgid "You are currently running version %1." +msgstr "" + +msgid "Version %1 is now available." +msgstr "" + +msgid "You are currently running build %1." +msgstr "" + +msgid "Build %1 is now available." +msgstr "" + +msgid "Would you like to visit the download page?" +msgstr "" + +msgid "Visit download page" +msgstr "" + +msgid "Update check" +msgstr "" + +msgid "Checking for updates…" +msgstr "Έλεγχος για ενημερώσεις…" + +msgid "86Box Update" +msgstr "" + +msgid "Release notes:" +msgstr "" + +msgid "%1 Hz" +msgstr "" + +msgid "Virtual machine crash" +msgstr "" + +msgid "The virtual machine \"%1\"'s process has unexpectedly terminated with exit code %2." +msgstr "" + +msgid "The system will not be added." +msgstr "" + +msgid "&Update mouse every CPU frame" +msgstr "&Ανανέωση ποντικιού ανα καρέ CPU" + +msgid "Hue" +msgstr "" + +msgid "Saturation" +msgstr "" + +msgid "Contrast" +msgstr "" + +msgid "Brightness" +msgstr "" + +msgid "Sharpness" +msgstr "" + +msgid "&CGA composite settings…" +msgstr "Ρυθμίσεις &CGA composite…" + +msgid "CGA composite settings" +msgstr "Ρυθμίσεις CGA composite" + +msgid "Monitor EDID" +msgstr "Οθόνη EDID" + +msgid "Export…" +msgstr "Εξαγωγή…" + +msgid "Export EDID" +msgstr "Εξαγωγή EDID" + +msgid "EDID file \"%ls\" is too large." +msgstr "Το αρχείο EDID \"%ls\" είναι πολύ μεγάλο." + +msgid "OpenGL input scale" +msgstr "Κλίμακα OpenGL input" + +msgid "OpenGL input stretch mode" +msgstr "OpenGL input σε λειτουργία τεντώματος" + +msgid "Color scheme" +msgstr "Συνδυασμός χρωμάτων" + +msgid "Light" +msgstr "Φωτεινό" + +msgid "Dark" +msgstr "Σκοτεινό" + +msgid "Search:" +msgstr "Αναζήτηση:" + +msgid "Force interpretation" +msgstr "Εξαναγκασμός ερμηνείας" + +msgid "Allow recompilation" +msgstr "Να επιτρέπεται ανασύνταξη" + +msgid "&Force interpretation" +msgstr "&Εξαναγκασμός ερμηνείας" + +msgid "&Allow recompilation" +msgstr "&Να επιτρέπεται ανασύνταξη" + +msgid "&Fast forward" +msgstr "" + +msgid "Fast forward" +msgstr "" + +msgid "To change the system directory, stop all running machines." +msgstr "" diff --git a/src/qt/languages/en-GB.po b/src/qt/languages/en-GB.po index ba9f30421f5..fdc71fcb102 100644 --- a/src/qt/languages/en-GB.po +++ b/src/qt/languages/en-GB.po @@ -12,6 +12,9 @@ msgstr "RGB &Colour" msgid "&RGB Grayscale" msgstr "&RGB Greyscale" +msgid "Generic RGBI color monitor" +msgstr "Generic RGBI colour monitor" + msgid "Time synchronization" msgstr "Time synchronisation" @@ -21,15 +24,15 @@ msgstr "Unable to initialise Ghostscript" msgid "Unable to initialize GhostPCL" msgstr "Unable to initialise GhostPCL" +msgid "Failed to initialize network driver" +msgstr "Failed to initialise network driver" + msgid "Development of the WinBox manager stopped in 2022 due to a lack of maintainers. As we direct our efforts towards making 86Box even better, we have made the decision to no longer support WinBox as a manager.\n\nNo further updates will be provided through WinBox, and you may encounter incorrect behavior should you continue using it with newer versions of 86Box. Any bug reports related to WinBox behavior will be closed as invalid.\n\nGo to 86box.net for a list of other managers you can use." msgstr "Development of the WinBox manager stopped in 2022 due to a lack of maintainers. As we direct our efforts towards making 86Box even better, we have made the decision to no longer support WinBox as a manager.\n\nNo further updates will be provided through WinBox, and you may encounter incorrect behavior should you continue using it with newer versions of 86Box. Any bug reports related to WinBox behaviour will be closed as invalid.\n\nGo to 86box.net for a list of other managers you can use." msgid "Appl&y fullscreen stretch mode when maximized" msgstr "Appl&y fullscreen stretch mode when maximised" -msgid "Failed to initialize network driver" -msgstr "Failed to initialise network driver" - msgid "Render behavior" msgstr "Render behaviour" @@ -42,6 +45,12 @@ msgstr "Error initialising OpenGL" msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" msgstr "

When selecting media images (CD-ROM, floppy, etc.) the open dialogue will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" +msgid "Invert colors" +msgstr "Invert colours" + +msgid "True color" +msgstr "True colour" + msgid "Color (generic)" msgstr "Colour (generic)" @@ -75,5 +84,5 @@ msgstr "Colour" msgid "Failed to initialize Vulkan renderer." msgstr "Failed to initialise Vulkan renderer." -msgid "True color" -msgstr "True colour" +msgid "Color scheme" +msgstr "Colour scheme" diff --git a/src/qt/languages/es-ES.po b/src/qt/languages/es-ES.po index a365d62aa5e..3d339efd01e 100644 --- a/src/qt/languages/es-ES.po +++ b/src/qt/languages/es-ES.po @@ -25,7 +25,7 @@ msgid "&Hard reset" msgstr "&Hard reset" msgid "&Ctrl+Alt+Del" -msgstr "&Ctrl+Alt+Del" +msgstr "&Ctrl+Alt+Supr" msgid "Ctrl+Alt+&Esc" msgstr "Ctrl+Alt+&Esc" @@ -72,8 +72,8 @@ msgstr "Open&GL (3.0 Core)" msgid "&VNC" msgstr "&VNC" -msgid "Specify &dimensions..." -msgstr "E&specificar dimensiones..." +msgid "Specify &dimensions…" +msgstr "E&specificar dimensiones…" msgid "Force &4:3 display ratio" msgstr "Forzar ratio &4:3" @@ -160,19 +160,19 @@ msgid "RGB (no brown)" msgstr "RGB (sin marrón)" msgid "&RGB Grayscale" -msgstr "RGB &Grises" +msgstr "RGB &grises" msgid "Generic RGBI color monitor" msgstr "Monitor a colores RGBI genérico" msgid "&Amber monitor" -msgstr "Monitor Ámb&ar" +msgstr "Monitor ámb&ar" msgid "&Green monitor" -msgstr "Monitor &Verde" +msgstr "Monitor &verde" msgid "&White monitor" -msgstr "Monitor &Blanco" +msgstr "Monitor &blanco" msgid "Grayscale &conversion type" msgstr "&Conversión a grises" @@ -198,11 +198,11 @@ msgstr "&Medios" msgid "&Tools" msgstr "&Herramientas" -msgid "&Settings..." -msgstr "&Configuraciones..." +msgid "&Settings…" +msgstr "&Configuraciones…" -msgid "Settings..." -msgstr "Configuraciones..." +msgid "Settings…" +msgstr "Configuraciones…" msgid "&Update status bar icons" msgstr "&Actualizar iconos en barra de estado" @@ -210,17 +210,38 @@ msgstr "&Actualizar iconos en barra de estado" msgid "Take s&creenshot" msgstr "Tomar cap&tura" +msgid "Take screenshot" +msgstr "Tomar captura" + +msgid "Take &raw screenshot" +msgstr "Tomar captura &plana" + +msgid "Take raw screenshot" +msgstr "Tomar captura plana" + +msgid "C&opy screenshot" +msgstr "C&opiar captura" + +msgid "Copy screenshot" +msgstr "Copiar captura" + +msgid "Copy r&aw screenshot" +msgstr "Copiar captura p&lana" + +msgid "Copy raw screenshot" +msgstr "Copiar captura plana" + msgid "S&ound" msgstr "S&onido" -msgid "&Preferences..." -msgstr "&Preferencias..." +msgid "&Preferences…" +msgstr "&Preferencias…" msgid "Enable &Discord integration" msgstr "Habilitar integración con &Discord" -msgid "Sound &gain..." -msgstr "&Ganancia de sonido..." +msgid "Sound &gain…" +msgstr "&Ganancia de sonido…" msgid "Begin trace" msgstr "Comenzar traza" @@ -231,20 +252,20 @@ msgstr "Terminar traza" msgid "&Help" msgstr "Ay&uda" -msgid "&Documentation..." -msgstr "&Documentación..." +msgid "&Documentation…" +msgstr "&Documentación…" -msgid "&About 86Box..." -msgstr "&Acerca de 86Box..." +msgid "&About 86Box…" +msgstr "&Acerca de 86Box…" -msgid "&New image..." -msgstr "&Nueva imagen..." +msgid "&New image…" +msgstr "&Nueva imagen…" -msgid "&Existing image..." -msgstr "Imagen &Existente..." +msgid "&Existing image…" +msgstr "Imagen &existente…" -msgid "Existing image (&Write-protected)..." -msgstr "Imagen Existente (&Sólo-lectura)..." +msgid "Existing image (&Write-protected)…" +msgstr "Imagen existente (&Sólo-lectura)…" msgid "&Record" msgstr "&Grabar" @@ -261,11 +282,11 @@ msgstr "&Avance rápido al final" msgid "E&ject" msgstr "E&xtraer" -msgid "&Image..." -msgstr "&Imagen..." +msgid "&Image…" +msgstr "&Imagen…" -msgid "E&xport to 86F..." -msgstr "E&xportar a 86F..." +msgid "E&xport to 86F…" +msgstr "E&xportar a 86F…" msgid "&Mute" msgstr "&Silenciar" @@ -276,23 +297,23 @@ msgstr "E&xtraer disco" msgid "Reload previous image" msgstr "Recargar imagen previa" -msgid "&Folder..." -msgstr "&Carpeta..." +msgid "&Folder…" +msgstr "&Carpeta…" msgid "Preferences" msgstr "Preferencias" msgid "Sound Gain" -msgstr "Ganancia de Sonido" +msgstr "Ganancia de sonido" msgid "New Image" -msgstr "Nueva Imagen" +msgstr "Nueva imagen" msgid "Settings" msgstr "Configuraciones" msgid "Specify Main Window Dimensions" -msgstr "Especificar Dimensiones de la Ventana Principal" +msgstr "Especificar dimensiones de la ventana principal" msgid "OK" msgstr "Aceptar" @@ -376,7 +397,7 @@ msgid "Enabled (UTC)" msgstr "Habilitado (UTC)" msgid "Dynamic Recompiler" -msgstr "Recompilador Dinámico" +msgstr "Recompilador dinámico" msgid "CPU frame size" msgstr "Tamaño de blocos de CPU" @@ -423,17 +444,17 @@ msgstr "Mando:" msgid "Joystick" msgstr "Mando" -msgid "Joystick 1..." -msgstr "Mando 1..." +msgid "Joystick 1…" +msgstr "Mando 1…" -msgid "Joystick 2..." -msgstr "Mando 2..." +msgid "Joystick 2…" +msgstr "Mando 2…" -msgid "Joystick 3..." -msgstr "Mando 3..." +msgid "Joystick 3…" +msgstr "Mando 3…" -msgid "Joystick 4..." -msgstr "Mando 4..." +msgid "Joystick 4…" +msgstr "Mando 4…" msgid "Sound card #1:" msgstr "Tarjeta de sonido 1:" @@ -522,10 +543,10 @@ msgstr "Puerto paralelo 3" msgid "Parallel port 4" msgstr "Puerto paralelo 4" -msgid "FD Controller:" -msgstr "Controladora FD:" +msgid "Floppy disk controller:" +msgstr "Controladora de disquetes:" -msgid "CD-ROM Controller:" +msgid "CD-ROM controller:" msgstr "Controladora CD-ROM:" msgid "Tertiary IDE Controller" @@ -534,11 +555,11 @@ msgstr "Tercera controladora IDE" msgid "Quaternary IDE Controller" msgstr "Cuarta controladora IDE" -msgid "Hard disk" -msgstr "Disco duro" +msgid "Hard disk controllers" +msgstr "Controladores de disco duro" -msgid "SCSI" -msgstr "SCSI" +msgid "SCSI controllers" +msgstr "Controladores SCSI" msgid "Controller 1:" msgstr "Controladora 1:" @@ -561,11 +582,11 @@ msgstr "Discos duros:" msgid "Firmware Version" msgstr "Versión de firmware" -msgid "&New..." -msgstr "&Nuevo..." +msgid "&New…" +msgstr "&Nuevo…" -msgid "&Existing..." -msgstr "&Existente..." +msgid "&Existing…" +msgstr "&Existente…" msgid "&Remove" msgstr "E&liminar" @@ -604,7 +625,7 @@ msgid "Floppy drives:" msgstr "Unidades de disquete:" msgid "Turbo timings" -msgstr "Temporizaciones Turbo" +msgstr "Temporizaciones turbo" msgid "Check BPB" msgstr "Chequear BPB" @@ -631,7 +652,7 @@ msgid "ISA RTC:" msgstr "ISA RTC:" msgid "ISA Memory Expansion" -msgstr "Expansión de Memoria ISA" +msgstr "Expansión de memoria ISA" msgid "ISA ROM Cards" msgstr "Tarjetas ROM ISA" @@ -682,7 +703,7 @@ msgid "&Removable disk %1 (%2): %3" msgstr "&Disco removible %1 (%2): %3" msgid "Removable disk images" -msgstr "Imagenes de disco removible" +msgstr "Imágenes de disco removible" msgid "Image %1" msgstr "Imagen %1" @@ -709,19 +730,19 @@ msgid "All images" msgstr "Todas las imagenes" msgid "Basic sector images" -msgstr "Basic sector images" +msgstr "Imágenes básicas de sector" msgid "Surface images" -msgstr "Surface images" +msgstr "Imágenes de superficie" msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." msgstr "La máquina \"%hs\" no está disponible debido a ROMs faltantes en el directorio roms/machines. Cambiando a una máquina disponible." msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video directory. Switching to an available video card." -msgstr "La tarjeta de vídeo \"%hs\" no está disponible debido a ROMs faltantes en el directorio roms/machines. Cambiando a una tarjeta de vídeo disponible." +msgstr "La tarjeta de vídeo \"%hs\" no está disponible debido a ROMs faltantes en el directorio roms/video. Cambiando a una tarjeta de vídeo disponible." msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." -msgstr "La tarjeta de vídeo 2 \"%hs\" no está disponible debido a ROMs faltantes en el directorio roms/machines. Deshabilitanto la segunda tarjeta de vídeo." +msgstr "La tarjeta de vídeo 2 \"%hs\" no está disponible debido a ROMs faltantes en el directorio roms/video. Deshabilitanto la segunda tarjeta de vídeo." msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." msgstr "El dispositivo \"%hs\" no está disponible debido a ROMs faltantes. Ignorando el dispositivo." @@ -733,7 +754,7 @@ msgid "Display" msgstr "Vídeo" msgid "Input devices" -msgstr "Dispositivos de Entrada" +msgstr "Dispositivos de entrada" msgid "Sound" msgstr "Sonido" @@ -754,10 +775,10 @@ msgid "Parallel ports:" msgstr "Puertos paralelos:" msgid "Storage controllers" -msgstr "Controladoras de Almacenamiento" +msgstr "Controladoras de almacenamiento" msgid "Hard disks" -msgstr "Discos Duros" +msgstr "Discos duros" msgid "Disks:" msgstr "Discos:" @@ -811,7 +832,7 @@ msgid "Default" msgstr "Por defecto" msgid "%1 Wait state(s)" -msgstr "%1 estado(s) de Espera" +msgstr "%1 estado(s) de espera" msgid "Type" msgstr "Tipo" @@ -873,9 +894,6 @@ msgstr "Mando de juegos de 4 botones" msgid "6-button gamepad" msgstr "Mando de juegos de 6 botones" -msgid "Gravis PC GamePad" -msgstr "Gravis PC GamePad" - msgid "2-button flight yoke" msgstr "Yugo de vuelo de 2 botones" @@ -903,51 +921,6 @@ msgstr "Volante (de 3 ejes, 3 botones)" msgid "Steering wheel (3-axis, 4-button)" msgstr "Volante (de 3 ejes, 4 botones)" -msgid "CH Flightstick" -msgstr "CH Flightstick" - -msgid "CH Flightstick + CH Pedals" -msgstr "CH Flightstick + CH Pedals" - -msgid "CH Flightstick + CH Pedals Pro" -msgstr "CH Flightstick + CH Pedals Pro" - -msgid "CH Flightstick Pro" -msgstr "CH Flightstick Pro" - -msgid "CH Flightstick Pro + CH Pedals" -msgstr "CH Flightstick Pro + CH Pedals" - -msgid "CH Flightstick Pro + CH Pedals Pro" -msgstr "CH Flightstick Pro + CH Pedals Pro" - -msgid "CH Virtual Pilot" -msgstr "CH Virtual Pilot" - -msgid "CH Virtual Pilot + CH Pedals" -msgstr "CH Virtual Pilot + CH Pedals" - -msgid "CH Virtual Pilot + CH Pedals Pro" -msgstr "CH Virtual Pilot + CH Pedals Pro" - -msgid "CH Virtual Pilot Pro" -msgstr "CH Virtual Pilot Pro" - -msgid "CH Virtual Pilot Pro + CH Pedals" -msgstr "CH Virtual Pilot Pro + CH Pedals" - -msgid "CH Virtual Pilot Pro + CH Pedals Pro" -msgstr "CH Virtual Pilot Pro + CH Pedals Pro" - -msgid "Microsoft SideWinder Pad" -msgstr "Microsoft SideWinder Pad" - -msgid "Thrustmaster Flight Control System" -msgstr "Thrustmaster Flight Control System" - -msgid "Thrustmaster FCS + Rudder Control System" -msgstr "Thrustmaster FCS + Rudder Control System" - msgid "Thrustmaster Formula T1/T2 with adapter" msgstr "Thrustmaster Formula T1/T2 con adaptador" @@ -994,7 +967,7 @@ msgid "MO images" msgstr "Imágenes de MO" msgid "Welcome to 86Box!" -msgstr "¡Bienvenido a 86Box!" +msgstr "¡Bienvenido en 86Box!" msgid "Internal device" msgstr "Dispositivo interno" @@ -1002,11 +975,17 @@ msgstr "Dispositivo interno" msgid "&File" msgstr "&Archivo" -msgid "&New machine..." -msgstr "&Nueva máquina..." +msgid "&New machine…" +msgstr "&Nueva máquina…" + +msgid "New machine…" +msgstr "Nueva máquina…" + +msgid "New machine" +msgstr "Nueva máquina" -msgid "&Check for updates..." -msgstr "&Verifica actualizaciones..." +msgid "&Check for updates…" +msgstr "&Verifica actualizaciones…" msgid "Exit" msgstr "Salir" @@ -1033,13 +1012,13 @@ msgid "Hardware not available" msgstr "Equipo no disponible" msgid "Make sure %1 is installed and that you are on a %1-compatible network connection." -msgstr "Asegúrate de que %1 está instalado y de que estás en una conexión de red compatible con %1." +msgstr "Asegúree de que %1 está instalado y de que estás en una conexión de red compatible con %1." msgid "Invalid configuration" msgstr "Configuración inválida" msgid "%1 is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." -msgstr "%1 es necesaria para la conversión automática de archivos PostScript a PDF.\n\nCualquier documento enviado a la impresora genérica postScript se guardará como archivo PostScript (.ps)." +msgstr "%1 es necesaria para la conversión automática de archivos PostScript a PDF.\n\nCualquier documento enviado a la impresora genérica PostScript se guardará como archivo PostScript (.ps)." msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny documents sent to the generic PCL printer will be saved as Printer Command Language (.pcl) files." msgstr "%1 es necesaria para la conversión automática de archivos PCL a PDF.\n\nCualquier documento enviado a la impresora genérica PCL se guardará como archivo Printer Command Language (.pcl)." @@ -1060,7 +1039,7 @@ msgid "CD-ROM images" msgstr "Imágenes de CD-ROM" msgid "%1 Device Configuration" -msgstr "%1 Configuración de Dispositivo" +msgstr "Configuración de dispositivo %1" msgid "Monitor in sleep mode" msgstr "Monitor en modo ahorro" @@ -1072,7 +1051,7 @@ msgid "You are loading an unsupported configuration" msgstr "Está cargando una configuración no soportada" msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." -msgstr "El Filtrado de tipo de CPU basado en máquina seleccionada está deshabilitado para la esta máquina.\n\nEsto hace posible seleccionar una CPU que sea incompatible con esta máquina. Por ello, pueden aparecer incompatibilidader con la BIOS de la máquina u otro software.\n\nActivar esta configuración no está oficialmente soportado y cualquier reporte de fallo puede ser cerrado como inválido." +msgstr "El filtrado de tipo de CPU basado en máquina seleccionada está deshabilitado para la esta máquina.\n\nEsto hace posible seleccionar una CPU que sea incompatible con esta máquina. Por ello, pueden aparecer incompatibilidader con la BIOS de la máquina u otro software.\n\nActivar esta configuración no está oficialmente soportado y cualquier reporte de fallo puede ser cerrado como inválido." msgid "Continue" msgstr "Continuar" @@ -1084,7 +1063,7 @@ msgid "C&assette: %1" msgstr "C&assette: %1" msgid "Cassette images" -msgstr "Imágenes de Cassette" +msgstr "Imágenes de cassette" msgid "Cartridge %1: %2" msgstr "Cartucho %1: %2" @@ -1093,7 +1072,7 @@ msgid "Car&tridge %1: %2" msgstr "Car&tucho %1: %2" msgid "Cartridge images" -msgstr "Imágenes de Cartucho" +msgstr "Imágenes de cartucho" msgid "Resume execution" msgstr "Retomar la ejecución" @@ -1102,7 +1081,7 @@ msgid "Pause execution" msgstr "Pausar la ejecución" msgid "Ctrl+Alt+Del" -msgstr "Ctrl+Alt+Del" +msgstr "Ctrl+Alt+Supr" msgid "Press Ctrl+Alt+Del" msgstr "Pulsar Ctrl+Alt+Supr" @@ -1114,13 +1093,13 @@ msgid "Hard reset" msgstr "Hard reset" msgid "Force shutdown" -msgstr "Apagqar forzadamente" +msgstr "Apagar forzadamente" msgid "Start" msgstr "Iniciar" msgid "&Force shutdown" -msgstr "&Apagqar forzadamente" +msgstr "&Apagar forzadamente" msgid "&Start" msgstr "&Iniciar" @@ -1176,8 +1155,8 @@ msgstr "No fúe posible abrir el archivo de configuración seleccionado para lee msgid "Use regular expressions in search box" msgstr "Utilizar expresiones regulares en la caja de búsqueda" -msgid "%1 machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" -msgstr "%1 máquina(s) son activas en este momento. ¿Está seguro de que quiere salir del administrador de MV?" +msgid "%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" +msgstr "%n máquina(s) son activas en este momento. ¿Está seguro de que quiere salir del administrador de MV?" msgid "Add new system wizard" msgstr "Asistente para la adición de un nuevo sistema" @@ -1234,7 +1213,7 @@ msgid "System location:" msgstr "Ubicación del sistema:" msgid "System name and location" -msgstr "Nombre y ubicaciónd el sistema" +msgstr "Nombre y ubicación del sistema" msgid "Enter the name of the system and choose the location" msgstr "Escribir el nombre del sistema y escoger la ubicación" @@ -1257,26 +1236,23 @@ msgstr "Establecer nombre mostrado" msgid "Enter the new display name (blank to reset)" msgstr "Escribir el nuevo nombre mostrado (vacío para restablecer)" -msgid "Change &display name..." -msgstr "Cambiar nombre &mostrado..." +msgid "Change &display name…" +msgstr "Cambiar nombre &mostrado…" -msgid "Context Menu" -msgstr "Menú de contexto" +msgid "&Open folder…" +msgstr "&Abrir carpeta…" -msgid "&Open folder..." -msgstr "&Abrir carpeta..." +msgid "Open p&rinter tray…" +msgstr "Abrir bandeja de la &impresora…" -msgid "Open p&rinter tray..." -msgstr "Abrir bandeja de la &impresora..." - -msgid "Set &icon..." -msgstr "Establecer &icono..." +msgid "Set &icon…" +msgstr "Establecer &icono…" msgid "Select an icon" msgstr "Escoger un icono" -msgid "C&lone..." -msgstr "C&lonar..." +msgid "C&lone…" +msgstr "C&lonar…" msgid "Virtual machine \"%1\" (%2) will be cloned into:" msgstr "La máquina virtual \"%1\" (%2) será clonada para:" @@ -1294,7 +1270,7 @@ msgid "Failed to create directory for cloned VM" msgstr "Error al crear el directório para la MV clonada" msgid "Failed to clone VM." -msgstr "Error al clonar la VM." +msgstr "Error al clonar la MV." msgid "Directory in use" msgstr "Directório en uso" @@ -1333,7 +1309,7 @@ msgid "An update to 86Box is available: %1 %2" msgstr "Está disponible una actualización para 86Box: %1 %2" msgid "An error has occurred while checking for updates: %1" -msgstr "Ha ocurrido un error al verificar las actualizacioens: %1" +msgstr "Ha ocurrido un error al verificar las actualizaciones: %1" msgid "An update to 86Box is available!" msgstr "¡Una actualización para 86Box está disponible!" @@ -1362,8 +1338,8 @@ msgstr "Sin captura de pantalla" msgid "Search" msgstr "Buscar" -msgid "Searching for VMs..." -msgstr "Buscar para MV..." +msgid "Searching for VMs…" +msgstr "Buscar para MV…" msgid "Found %1" msgstr "%1 encontrada" @@ -1398,17 +1374,17 @@ msgstr "Disco duro (%1)" msgid "MFM/RLL or ESDI CD-ROM drives never existed" msgstr "Nunca existieron unidades de CD-ROM MFM/RLL o ESDI" -msgid "Custom..." -msgstr "A medida..." +msgid "Custom…" +msgstr "A medida…" -msgid "Custom (large)..." -msgstr "A medida (grande)..." +msgid "Custom (large)…" +msgstr "A medida (grande)…" msgid "Add New Hard Disk" -msgstr "Añadir Nuevo Disco Duro" +msgstr "Añadir nuevo disco duro" msgid "Add Existing Hard Disk" -msgstr "Añadir Disco Duro Existente" +msgstr "Añadir disco duro existente" msgid "HDI disk images cannot be larger than 4 GB." msgstr "Las imágenes de disco HDI no pueden superar los 4 GB." @@ -1417,7 +1393,7 @@ msgid "Disk images cannot be larger than 127 GB." msgstr "Las imágenes de disco no pueden superar los 127 GB." msgid "Hard disk images" -msgstr "Imágenes de Disco Duro" +msgstr "Imágenes de disco duro" msgid "Unable to read file" msgstr "No se pudo leer el archivo" @@ -1521,21 +1497,6 @@ msgstr "Las marcas de tiempo del padre e hijo no coinciden" msgid "Could not fix VHD timestamp." msgstr "No fué posible corregir la marca de tiempo del VHD." -msgid "MFM/RLL" -msgstr "MFM/RLL" - -msgid "XTA" -msgstr "XTA" - -msgid "ESDI" -msgstr "ESDI" - -msgid "IDE" -msgstr "IDE" - -msgid "ATAPI" -msgstr "ATAPI" - msgid "CD-ROM %1 (%2): %3" msgstr "CD-ROM %1 (%2): %3" @@ -1686,14 +1647,14 @@ msgstr "Herramienta de tableta" msgid "About &Qt" msgstr "Acerca de &Qt" -msgid "&MCA devices..." -msgstr "Dispositivos MCA ..." +msgid "&MCA devices…" +msgstr "Dispositivos MCA…" msgid "Show non-&primary monitors" msgstr "Mostrar monitores no prim&arios" -msgid "Open screenshots &folder..." -msgstr "Abrir la ca&rpeta screenshots..." +msgid "Open screenshots &folder…" +msgstr "Abrir la ca&rpeta screenshots…" msgid "Appl&y fullscreen stretch mode when maximized" msgstr "&Usar escalado pantalla completa en modalidad maximizada" @@ -1713,8 +1674,8 @@ msgstr "&Conectrado" msgid "Clear image &history" msgstr "Eliminar &historia de imágenes" -msgid "Create..." -msgstr "Crear..." +msgid "Create…" +msgstr "Crear…" msgid "Host CD/DVD Drive (%1)" msgstr "Unidad de CD/DVD anfitriona (%1)" @@ -1755,8 +1716,8 @@ msgstr "Shaders" msgid "Remove" msgstr "Eliminar" -msgid "Browse..." -msgstr "Buscar..." +msgid "Browse…" +msgstr "Buscar…" msgid "Couldn't create OpenGL context." msgstr "No ha sido posible crear el contexto OpenGL." @@ -1792,7 +1753,7 @@ msgid "86Box Monitor #%1" msgstr "Monitor de 86Box %1" msgid "No MCA devices." -msgstr "No hay dispositovos MCA." +msgstr "No hay dispositivos MCA." msgid "MiB" msgstr "MiB" @@ -1845,8 +1806,8 @@ msgstr "Paso de puerto serie 3" msgid "Serial port passthrough 4" msgstr "Paso de puerto serie 4" -msgid "Renderer &options..." -msgstr "Opc&iones del renderizador..." +msgid "Renderer &options…" +msgstr "Opc&iones del renderizador…" msgid "PC/XT Keyboard" msgstr "Teclado PC/XT" @@ -1899,8 +1860,8 @@ msgstr "3M MicroTouch (serie)" msgid "Default Baud rate" msgstr "Velocidad de transmisión pretederminada" -msgid "[COM] Standard Hayes-compliant Modem" -msgstr "[COM] Módem estándar compatible con Hayes" +msgid "Standard Hayes-compliant Modem" +msgstr "Módem estándar compatible con Hayes" msgid "Roland MT-32 Emulation" msgstr "Emulación Roland MT-32" @@ -1983,6 +1944,9 @@ msgstr "IRQ del puerto serie" msgid "Parallel port IRQ" msgstr "IRQ del puerto paralelo" +msgid "Hard disk" +msgstr "Disco duro" + msgid "BIOS Revision" msgstr "Revisión de BIOS" @@ -2058,9 +2022,6 @@ msgstr "Atravesar la entrada MIDI" msgid "MIDI Clockout" msgstr "Salida de reloj MIDI" -msgid "SoundFont" -msgstr "SoundFont" - msgid "Output Gain" msgstr "Ganancia de salida" @@ -2179,7 +2140,7 @@ msgid "MPU-401 Address" msgstr "Dirección del MPU-401" msgid "MPU-401 IRQ" -msgstr "IQ del MPU-401" +msgstr "IRQ del MPU-401" msgid "Receive MIDI input" msgstr "Recebir entrada MIDI" @@ -2275,7 +2236,7 @@ msgid "Display type" msgstr "Tipo de pantalla" msgid "Composite type" -msgstr "Tipo de pantalla compuesta" +msgstr "Tipo de pantalla compósita" msgid "RGB type" msgstr "Tipo de pantalla RGB" @@ -2503,7 +2464,7 @@ msgid "256 KB" msgstr "256 KB" msgid "Composite" -msgstr "Compuesto" +msgstr "Compósito" msgid "True color" msgstr "Verdadero color" @@ -2539,13 +2500,13 @@ msgid "sRGB interpolation" msgstr "Interpolación sRGB" msgid "Linear interpolation" -msgstr "Interpolación lineare" +msgstr "Interpolación lineal" msgid "Has secondary 8x8 character set" msgstr "Tiene conjunto de carácteres 8x8 secundário" msgid "Has Quadcolor II daughter board" -msgstr "Tiene tarjeta hija Quadcolor II" +msgstr "Tiene placa hija Quadcolor II" msgid "Alternate monochrome contrast" msgstr "Contraste monocromo alternativo" @@ -2626,7 +2587,7 @@ msgid "Obsidian SB50 + Amethyst (2 TMUs)" msgstr "Obsidian SB50 + Amethyst (2 unidades TMU)" msgid "8-bit" -msgstr "8 bitss" +msgstr "8 bits" msgid "16-bit" msgstr "16 bits" @@ -2653,7 +2614,7 @@ msgid "Generic Text Printer" msgstr "Impresora genérica de texto" msgid "Generic ESC/P 2 Dot-Matrix Printer" -msgstr "Impresora matricial ESC/P 2 genérica" +msgstr "Impresora genérica matricial ESC/P 2" msgid "Generic PostScript Printer" msgstr "Impresora genérica PostScript" @@ -2746,16 +2707,16 @@ msgid "60 Hz (JMP2 = 2)" msgstr "60 Hz (JMP2 = 2)" msgid "Generic PC/XT Memory Expansion" -msgstr "Expansión de Memoria Generica PC/XT" +msgstr "Expansión de memoria generica PC/XT" msgid "Generic PC/AT Memory Expansion" -msgstr "Expansión de Memoria Generica PC/AT" +msgstr "Expansión de memoria generica PC/AT" msgid "Unable to find Dot-Matrix fonts" msgstr "No fué posible encontrar las fuentes matriciales" msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for the emulation of the Generic ESC/P 2 Dot-Matrix Printer." -msgstr "Las fuentes TrueType en el directorio \"roms/printer/fonts\" son necesarias para la emulación de la impresora matricial ESC/P 2 genérica." +msgstr "Las fuentes TrueType en el directorio \"roms/printer/fonts\" son necesarias para la emulación de la impresora genérica matricial ESC/P 2." msgid "Inhibit multimedia keys" msgstr "Inhibir teclas multimedia" @@ -2842,7 +2803,7 @@ msgid "This key combo is already in use." msgstr "Esta combinación de teclas ya está en uso." msgid "Send Control+Alt+Del" -msgstr "Enviar Control+Alt+Del" +msgstr "Enviar Control+Alt+Supr" msgid "Send Control+Alt+Escape" msgstr "Enviar Control+Alt+Escape" @@ -2853,9 +2814,6 @@ msgstr "Alternar pantalla completa" msgid "Toggle UI in fullscreen" msgstr "Alternar interfaz de usuario en modo de pantalla completa" -msgid "Screenshot" -msgstr "Captura de pantalla" - msgid "Release mouse pointer" msgstr "Soltar el puntero del ratón" @@ -2899,7 +2857,7 @@ msgid "&Wipe NVRAM" msgstr "&Limpiar el NVRAM" msgid "This will delete all NVRAM (and related) files of the virtual machine located in the \"nvr\" subdirectory. You'll have to reconfigure the BIOS (and possibly other devices inside the VM) settings again if applicable.\n\nAre you sure you want to wipe all NVRAM contents of the virtual machine \"%1\"?" -msgstr "Estó borrará todos los archivos de NVRAM (y relacionados) de la máquina virtual ubicados en el subdirectório \"nvr\". Tendrá que reconifigurar la definiciones del BIOS (y talvez de otros dispositivoes dentro de la MV) otra vez si aplicable.\n\n¿Está seguro de que quierere limpiar todos los contenidos de la NVRAM de la máquina virtual \"%1\"?" +msgstr "Estó borrará todos los archivos de NVRAM (y relacionados) de la máquina virtual ubicados en el subdirectório \"nvr\". Tendrá que reconfigurar la definiciones del BIOS (y tal vez de otros dispositivos dentro de la MV) otra vez si aplicable.\n\n¿Está seguro de que quiere limpiar todos los contenidos de la NVRAM de la máquina virtual \"%1\"?" msgid "Success" msgstr "Éxito" @@ -2920,10 +2878,10 @@ msgid "Unknown Status" msgstr "Estado desconocido" msgid "No Machines Found!" -msgstr "¡No fueron encontradas máquinas!" +msgstr "¡No fueran encontradas máquinas!" msgid "Check for updates on startup" -msgstr "Contorlar actualizaciones al iniciar" +msgstr "Verificar actualizaciones al iniciar" msgid "Unable to determine release information" msgstr "No fué posible determinar informaciones de la versión" @@ -2956,7 +2914,7 @@ msgid "Version %1 is now available." msgstr "La versión %1 está ahora disponible." msgid "You are currently running build %1." -msgstr "Actualmente está a ejecutar la compialación %1." +msgstr "Actualmente está a ejecutar la compilación %1." msgid "Build %1 is now available." msgstr "La compilación %1 está ahora disponible." @@ -2970,8 +2928,8 @@ msgstr "Visitar a la página de descargas" msgid "Update check" msgstr "Verificación de actualizaciones" -msgid "Checking for updates..." -msgstr "Verificando las actualizaciones..." +msgid "Checking for updates…" +msgstr "Verificando las actualizaciones…" msgid "86Box Update" msgstr "Actualización de 86Box" @@ -3009,20 +2967,20 @@ msgstr "Brillo" msgid "Sharpness" msgstr "Nitidez" -msgid "&CGA composite settings..." -msgstr "Configuración del modo compuesto &CGA..." +msgid "&CGA composite settings…" +msgstr "Configuración del modo compósito &CGA…" msgid "CGA composite settings" -msgstr "Configuración del modo compuesto CGA" +msgstr "Configuración del modo compósito CGA" msgid "Monitor EDID" -msgstr "EDID du moniteur" +msgstr "EDID del monitor" -msgid "Export..." -msgstr "Exporter..." +msgid "Export…" +msgstr "Exportar…" msgid "Export EDID" -msgstr "EDID exportieren" +msgstr "Exportar el EDID" msgid "EDID file \"%ls\" is too large." msgstr "El archivo EDID \"%ls\" es demasiado grande." @@ -3037,10 +2995,31 @@ msgid "Color scheme" msgstr "Esquema de colores" msgid "Light" -msgstr "Luz" +msgstr "Claro" msgid "Dark" msgstr "Oscuro" msgid "Search:" msgstr "Buscar:" + +msgid "Force interpretation" +msgstr "Forzar interpretación" + +msgid "Allow recompilation" +msgstr "Permitir recompilación" + +msgid "&Force interpretation" +msgstr "&Forzar interpretación" + +msgid "&Allow recompilation" +msgstr "&Permitir recompilación" + +msgid "&Fast forward" +msgstr "" + +msgid "Fast forward" +msgstr "" + +msgid "To change the system directory, stop all running machines." +msgstr "" diff --git a/src/qt/languages/fi-FI.po b/src/qt/languages/fi-FI.po index ce6d6bab449..fd6add6960a 100644 --- a/src/qt/languages/fi-FI.po +++ b/src/qt/languages/fi-FI.po @@ -1,8 +1,14 @@ msgid "" msgstr "" +"PO-Revision-Date: 2025-12-29 09:54+0000\n" +"Last-Translator: Daniel Gurney \n" +"Language-Team: Finnish \n" +"Language: fi-FI\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.12.2\n" "X-Language: fi_FI\n" "X-Source-Language: en_US\n" @@ -28,10 +34,10 @@ msgid "&Pause" msgstr "&Tauko" msgid "Pause" -msgstr "" +msgstr "Tauko" msgid "Re&sume" -msgstr "" +msgstr "&Jatka" msgid "E&xit" msgstr "&Poistu" @@ -66,8 +72,8 @@ msgstr "Open&GL (3.0 Core)" msgid "&VNC" msgstr "&VNC" -msgid "Specify &dimensions..." -msgstr "&Määritä koko..." +msgid "Specify &dimensions…" +msgstr "&Määritä koko…" msgid "Force &4:3 display ratio" msgstr "Pakota &4:3-kuvasuhde" @@ -157,7 +163,7 @@ msgid "&RGB Grayscale" msgstr "&RGB, harmaasävy" msgid "Generic RGBI color monitor" -msgstr "" +msgstr "Yleinen RGBI-värinäyttö" msgid "&Amber monitor" msgstr "&Meripihkanvärinen" @@ -192,11 +198,11 @@ msgstr "&Media" msgid "&Tools" msgstr "Työ&kalut" -msgid "&Settings..." -msgstr "&Asetukset..." +msgid "&Settings…" +msgstr "&Asetukset…" -msgid "Settings..." -msgstr "Asetukset..." +msgid "Settings…" +msgstr "Asetukset…" msgid "&Update status bar icons" msgstr "&Päivitä tilapalkin kuvakkeita" @@ -204,17 +210,38 @@ msgstr "&Päivitä tilapalkin kuvakkeita" msgid "Take s&creenshot" msgstr "Ota &kuvakaappaus" +msgid "Take screenshot" +msgstr "Ota kuvakaappaus" + +msgid "Take &raw screenshot" +msgstr "Ota &raaka kuvakaappaus" + +msgid "Take raw screenshot" +msgstr "Ota raaka kuvakaappaus" + +msgid "C&opy screenshot" +msgstr "K&opioi kuvakaappaus" + +msgid "Copy screenshot" +msgstr "Kopioi kuvakaappaus" + +msgid "Copy r&aw screenshot" +msgstr "Kopioi r&aaka kuvakaappaus" + +msgid "Copy raw screenshot" +msgstr "Kopioi raaka kuvakaappaus" + msgid "S&ound" msgstr "&Ääni" -msgid "&Preferences..." -msgstr "&Sovellusasetukset..." +msgid "&Preferences…" +msgstr "&Sovellusasetukset…" msgid "Enable &Discord integration" msgstr "&Discord-integraatio" -msgid "Sound &gain..." -msgstr "&Äänitasot..." +msgid "Sound &gain…" +msgstr "&Äänitasot…" msgid "Begin trace" msgstr "Aloita jäljitys" @@ -225,20 +252,20 @@ msgstr "Lopeta jäljitys" msgid "&Help" msgstr "&Ohje" -msgid "&Documentation..." -msgstr "&Ohjekirja..." +msgid "&Documentation…" +msgstr "&Ohjekirja…" -msgid "&About 86Box..." -msgstr "&Tietoja 86Boxista..." +msgid "&About 86Box…" +msgstr "&Tietoja 86Boxista…" -msgid "&New image..." -msgstr "&Uusi levykuva..." +msgid "&New image…" +msgstr "&Uusi levykuva…" -msgid "&Existing image..." -msgstr "&Olemassaoleva levykuva..." +msgid "&Existing image…" +msgstr "&Olemassaoleva levykuva…" -msgid "Existing image (&Write-protected)..." -msgstr "Olemassaoleva levykuva (&kirjoitussuojattu)..." +msgid "Existing image (&Write-protected)…" +msgstr "Olemassaoleva levykuva (&kirjoitussuojattu)…" msgid "&Record" msgstr "&Nauhoita" @@ -255,11 +282,11 @@ msgstr "Kelaa &loppuun" msgid "E&ject" msgstr "&Irrota" -msgid "&Image..." -msgstr "&Levykuva..." +msgid "&Image…" +msgstr "&Levykuva…" -msgid "E&xport to 86F..." -msgstr "&Vie 86F-tiedostoon..." +msgid "E&xport to 86F…" +msgstr "&Vie 86F-tiedostoon…" msgid "&Mute" msgstr "&Mykistä" @@ -270,8 +297,8 @@ msgstr "&Tyhjä" msgid "Reload previous image" msgstr "Lataa edellinen levykuva uudelleen" -msgid "&Folder..." -msgstr "&Kansio..." +msgid "&Folder…" +msgstr "&Kansio…" msgid "Preferences" msgstr "Sovellusasetukset" @@ -283,7 +310,7 @@ msgid "New Image" msgstr "Uusi levykuva" msgid "Settings" -msgstr "Kokoonpano" +msgstr "Asetukset" msgid "Specify Main Window Dimensions" msgstr "Määritä pääikkunan koko" @@ -334,7 +361,7 @@ msgid "Configure" msgstr "Määritys" msgid "CPU:" -msgstr "" +msgstr "Suoritin:" msgid "CPU type:" msgstr "Suorittimen tyyppi:" @@ -409,25 +436,25 @@ msgid "Mouse:" msgstr "Hiiri:" msgid "Mouse" -msgstr "" +msgstr "Hiiri" msgid "Joystick:" msgstr "Peliohjain:" msgid "Joystick" -msgstr "" +msgstr "Peliohjain" -msgid "Joystick 1..." -msgstr "Peliohjain 1..." +msgid "Joystick 1…" +msgstr "Peliohjain 1…" -msgid "Joystick 2..." -msgstr "Peliohjain 2..." +msgid "Joystick 2…" +msgstr "Peliohjain 2…" -msgid "Joystick 3..." -msgstr "Peliohjain 3..." +msgid "Joystick 3…" +msgstr "Peliohjain 3…" -msgid "Joystick 4..." -msgstr "Peliohjain 4..." +msgid "Joystick 4…" +msgstr "Peliohjain 4…" msgid "Sound card #1:" msgstr "Äänikortti 1:" @@ -516,10 +543,10 @@ msgstr "Rinnakkaisportti 3" msgid "Parallel port 4" msgstr "Rinnakkaisportti 4" -msgid "FD Controller:" +msgid "Floppy disk controller:" msgstr "Levykeohjain:" -msgid "CD-ROM Controller:" +msgid "CD-ROM controller:" msgstr "CD-ohjain:" msgid "Tertiary IDE Controller" @@ -528,11 +555,11 @@ msgstr "Kolmas IDE-ohjain" msgid "Quaternary IDE Controller" msgstr "Neljäs IDE-ohjain" -msgid "Hard disk" -msgstr "Kiintolevy" +msgid "Hard disk controllers" +msgstr "Kiintolevyohjaimet" -msgid "SCSI" -msgstr "SCSI" +msgid "SCSI controllers" +msgstr "SCSI-ohjaimet" msgid "Controller 1:" msgstr "Ohjain 1:" @@ -555,11 +582,11 @@ msgstr "Kiintolevyt:" msgid "Firmware Version" msgstr "Laiteohjelmiston versio" -msgid "&New..." -msgstr "&Uusi..." +msgid "&New…" +msgstr "&Uusi…" -msgid "&Existing..." -msgstr "&Olemassaoleva..." +msgid "&Existing…" +msgstr "&Olemassaoleva…" msgid "&Remove" msgstr "&Poista" @@ -643,13 +670,13 @@ msgid "Card 4:" msgstr "Kortti 4:" msgid "Generic ISA ROM Board" -msgstr "" +msgstr "Yleinen ISA ROM-kortti" msgid "Generic Dual ISA ROM Board" -msgstr "" +msgstr "Yleinen Dual ISA ROM-kortti" msgid "Generic Quad ISA ROM Board" -msgstr "" +msgstr "Yleinen Quad ISA ROM-kortti" msgid "ISABugger device" msgstr "ISABugger-laite" @@ -867,9 +894,6 @@ msgstr "4-painikkeinen peliohjain" msgid "6-button gamepad" msgstr "6-painikkeinen peliohjain" -msgid "Gravis PC GamePad" -msgstr "Gravis PC GamePad" - msgid "2-button flight yoke" msgstr "2-painikkeinen lento-ohjain" @@ -897,51 +921,6 @@ msgstr "ratti (3-akselinen, 3-painikkeinen)" msgid "Steering wheel (3-axis, 4-button)" msgstr "ratti (3-akselinen, 4-painikkeinen)" -msgid "CH Flightstick" -msgstr "CH Flightstick" - -msgid "CH Flightstick + CH Pedals" -msgstr "CH Flightstick + CH Pedals" - -msgid "CH Flightstick + CH Pedals Pro" -msgstr "CH Flightstick + CH Pedals Pro" - -msgid "CH Flightstick Pro" -msgstr "CH Flightstick Pro" - -msgid "CH Flightstick Pro + CH Pedals" -msgstr "CH Flightstick Pro + CH Pedals" - -msgid "CH Flightstick Pro + CH Pedals Pro" -msgstr "CH Flightstick Pro + CH Pedals Pro" - -msgid "CH Virtual Pilot" -msgstr "CH Virtual Pilot" - -msgid "CH Virtual Pilot + CH Pedals" -msgstr "CH Virtual Pilot + CH Pedals" - -msgid "CH Virtual Pilot + CH Pedals Pro" -msgstr "CH Virtual Pilot + CH Pedals Pro" - -msgid "CH Virtual Pilot Pro" -msgstr "CH Virtual Pilot Pro" - -msgid "CH Virtual Pilot Pro + CH Pedals" -msgstr "CH Virtual Pilot Pro + CH Pedals" - -msgid "CH Virtual Pilot Pro + CH Pedals Pro" -msgstr "CH Virtual Pilot Pro + CH Pedals Pro" - -msgid "Microsoft SideWinder Pad" -msgstr "Microsoft SideWinder Pad" - -msgid "Thrustmaster Flight Control System" -msgstr "Thrustmaster Flight Control System" - -msgid "Thrustmaster FCS + Rudder Control System" -msgstr "Thrustmaster FCS + Rudder Control System" - msgid "Thrustmaster Formula T1/T2 with adapter" msgstr "Thrustmaster Formula T1/T2 adapterilla" @@ -996,11 +975,17 @@ msgstr "Sisäinen laite" msgid "&File" msgstr "&Tiedosto" -msgid "&New machine..." -msgstr "&Uusi kone..." +msgid "&New machine…" +msgstr "&Uusi kone…" + +msgid "New machine…" +msgstr "Uusi kone…" + +msgid "New machine" +msgstr "Uusi kone" -msgid "&Check for updates..." -msgstr "T&arkista päivitykset..." +msgid "&Check for updates…" +msgstr "T&arkista päivitykset…" msgid "Exit" msgstr "Poistu" @@ -1170,8 +1155,8 @@ msgstr "Valittua määritystä ei voitu avata: %1" msgid "Use regular expressions in search box" msgstr "Käytä säännöllisiä lausekkeita (regex) hakukentässä" -msgid "%1 machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" -msgstr "%1 konetta on tällä hetkellä aktiivisena. Haluatko silti sulkea virtuaalikoneiden hallinnan?" +msgid "%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" +msgstr "%n konetta on tällä hetkellä aktiivisena. Haluatko silti sulkea virtuaalikoneiden hallinnan?" msgid "Add new system wizard" msgstr "Koneenlisäysohjelma" @@ -1251,26 +1236,23 @@ msgstr "Aseta näyttönimi" msgid "Enter the new display name (blank to reset)" msgstr "Anna uusi näyttönimi tai poista se" -msgid "Change &display name..." -msgstr "Vaihda &näyttönimi..." +msgid "Change &display name…" +msgstr "Vaihda &näyttönimi…" -msgid "Context Menu" -msgstr "Kontekstivalikko" +msgid "&Open folder…" +msgstr "&Avaa kansio…" -msgid "&Open folder..." -msgstr "&Avaa kansio..." +msgid "Open p&rinter tray…" +msgstr "Avaa &tulostimen lokero…" -msgid "Open p&rinter tray..." -msgstr "Avaa &tulostimen lokero..." - -msgid "Set &icon..." -msgstr "Aseta &kuvake..." +msgid "Set &icon…" +msgstr "Aseta &kuvake…" msgid "Select an icon" msgstr "Valitse kuvake" -msgid "C&lone..." -msgstr "K&loonaa..." +msgid "C&lone…" +msgstr "K&loonaa…" msgid "Virtual machine \"%1\" (%2) will be cloned into:" msgstr "Virtuaalikone \"%1\" (%2) kloonataan tänne:" @@ -1356,8 +1338,8 @@ msgstr "Ei kuvakaappausta" msgid "Search" msgstr "Hae" -msgid "Searching for VMs..." -msgstr "Haetaan virtuaalikoneita..." +msgid "Searching for VMs…" +msgstr "Haetaan virtuaalikoneita…" msgid "Found %1" msgstr "%1 löydetty" @@ -1392,11 +1374,11 @@ msgstr "Kiintolevy (%1)" msgid "MFM/RLL or ESDI CD-ROM drives never existed" msgstr "MFM/RLL- tai ESDI-CD-ROM-asemia ei ole koskaan ollut olemassa" -msgid "Custom..." -msgstr "Mukautettu..." +msgid "Custom…" +msgstr "Mukautettu…" -msgid "Custom (large)..." -msgstr "Mukautettu (suuri)..." +msgid "Custom (large)…" +msgstr "Mukautettu (suuri)…" msgid "Add New Hard Disk" msgstr "Lisää uusi kiintolevy" @@ -1515,21 +1497,6 @@ msgstr "Ylä- ja alatason levyjen aikaleimat eivät täsmää" msgid "Could not fix VHD timestamp." msgstr "VHD:n aikaleimaa ei pystytty korjaamaan." -msgid "MFM/RLL" -msgstr "MFM/RLL" - -msgid "XTA" -msgstr "XTA" - -msgid "ESDI" -msgstr "ESDI" - -msgid "IDE" -msgstr "IDE" - -msgid "ATAPI" -msgstr "ATAPI" - msgid "CD-ROM %1 (%2): %3" msgstr "CD-ROM %1 (%2): %3" @@ -1680,14 +1647,14 @@ msgstr "Tablettityökalu" msgid "About &Qt" msgstr "Tietoja &Qt:sta" -msgid "&MCA devices..." -msgstr "MCA-laitteet..." +msgid "&MCA devices…" +msgstr "MCA-laitteet…" msgid "Show non-&primary monitors" msgstr "Näytä muut kuin ensisijaiset näytöt" -msgid "Open screenshots &folder..." -msgstr "Avaa kuvakaappaukset-kansio..." +msgid "Open screenshots &folder…" +msgstr "Avaa kuvakaappaukset-kansio…" msgid "Appl&y fullscreen stretch mode when maximized" msgstr "Sovella koko näytön venytystilaa maksimoidessa" @@ -1707,8 +1674,8 @@ msgstr "&Yhdistetty" msgid "Clear image &history" msgstr "Tyhjennä levykuva&historia" -msgid "Create..." -msgstr "Luo..." +msgid "Create…" +msgstr "Luo…" msgid "Host CD/DVD Drive (%1)" msgstr "Isännän CD/DVD-asema (%1)" @@ -1749,8 +1716,8 @@ msgstr "Varjostinohjelmat" msgid "Remove" msgstr "Poista" -msgid "Browse..." -msgstr "Selaa..." +msgid "Browse…" +msgstr "Selaa…" msgid "Couldn't create OpenGL context." msgstr "OpenGL-kontekstia ei voitu luoda." @@ -1819,7 +1786,7 @@ msgid "VDE Socket:" msgstr "VDE-socket:" msgid "TAP Bridge Device:" -msgstr "" +msgstr "TAP-siltalaite:" msgid "86Box Unit Tester" msgstr "86Box Unit Tester" @@ -1839,8 +1806,8 @@ msgstr "Sarjaportin läpivienti 3" msgid "Serial port passthrough 4" msgstr "Sarjaportin läpivienti 4" -msgid "Renderer &options..." -msgstr "Renderöijän &asetukset..." +msgid "Renderer &options…" +msgstr "Renderöijän &asetukset…" msgid "PC/XT Keyboard" msgstr "PC/XT-näppäimistö" @@ -1870,7 +1837,7 @@ msgid "Mouse Systems Serial Mouse" msgstr "Mouse Systems-sarjahiiri" msgid "Mouse Systems Bus Mouse" -msgstr "" +msgstr "Mouse Systems Bus-hiiri" msgid "Microsoft Serial Mouse" msgstr "Microsoft-sarjahiiri" @@ -1893,8 +1860,8 @@ msgstr "3M MicroTouch (sarja)" msgid "Default Baud rate" msgstr "Oletussiirtonopeus" -msgid "[COM] Standard Hayes-compliant Modem" -msgstr "[COM] Tavallinen Hayes-yhteensopiva modeemi" +msgid "Standard Hayes-compliant Modem" +msgstr "Tavallinen Hayes-yhteensopiva modeemi" msgid "Roland MT-32 Emulation" msgstr "Roland MT-32-emulointi" @@ -1977,6 +1944,9 @@ msgstr "Sarjaportin IRQ" msgid "Parallel port IRQ" msgstr "Rinnakkaisportin IRQ" +msgid "Hard disk" +msgstr "Kiintolevy" + msgid "BIOS Revision" msgstr "BIOS-versio" @@ -2052,9 +2022,6 @@ msgstr "MIDI-läpivienti" msgid "MIDI Clockout" msgstr "MIDI-kellon ulostulo" -msgid "SoundFont" -msgstr "SoundFont" - msgid "Output Gain" msgstr "Lähtötaso" @@ -2116,7 +2083,7 @@ msgid "Serial Port" msgstr "Sarjaportti" msgid "RTS toggle" -msgstr "" +msgstr "RTS-kytkin" msgid "Revision" msgstr "Versio" @@ -2215,13 +2182,13 @@ msgid "RTC IRQ" msgstr "" msgid "RTC Port Address" -msgstr "" +msgstr "RTC-portin osoite" msgid "Onboard RTC" -msgstr "" +msgstr "Sisäänrakennettu RTC" msgid "Not installed" -msgstr "" +msgstr "Ei asennettu" msgid "Enable OPL" msgstr "OPL" @@ -2536,10 +2503,10 @@ msgid "Linear interpolation" msgstr "Lineaarinen interpolointi" msgid "Has secondary 8x8 character set" -msgstr "" +msgstr "Vaihtoehtoinen 8x8-merkistö" msgid "Has Quadcolor II daughter board" -msgstr "" +msgstr "Quadcolor II-tytärkortti" msgid "Alternate monochrome contrast" msgstr "Vaihtoehtoinen yksivärikontrasti" @@ -2596,7 +2563,7 @@ msgid "Bochs latest" msgstr "Uusin Bochs" msgid "Apply overscan deltas" -msgstr "" +msgstr "Käytä yliskannausdeltoja" msgid "Mono Interlaced" msgstr "Lomitettu yksivärinen" @@ -2845,10 +2812,7 @@ msgid "Toggle fullscreen" msgstr "Koko näyttö" msgid "Toggle UI in fullscreen" -msgstr "" - -msgid "Screenshot" -msgstr "Kuvakaappaus" +msgstr "Käyttöliittymä koko näyttö-tilassa" msgid "Release mouse pointer" msgstr "Vapauta hiiren osoitin" @@ -2964,8 +2928,8 @@ msgstr "Siirry lataussivulle" msgid "Update check" msgstr "Päivitystarkistus" -msgid "Checking for updates..." -msgstr "Tarkistetaan päivityksiä..." +msgid "Checking for updates…" +msgstr "Tarkistetaan päivityksiä…" msgid "86Box Update" msgstr "86Box-päivitys" @@ -3003,8 +2967,8 @@ msgstr "Kirkkaus" msgid "Sharpness" msgstr "Terävyys" -msgid "&CGA composite settings..." -msgstr "&CGA:n komposiittiasetukset..." +msgid "&CGA composite settings…" +msgstr "&CGA:n komposiittiasetukset…" msgid "CGA composite settings" msgstr "CGA:n komposiittiasetukset" @@ -3012,8 +2976,8 @@ msgstr "CGA:n komposiittiasetukset" msgid "Monitor EDID" msgstr "Näytön EDID" -msgid "Export..." -msgstr "Vie..." +msgid "Export…" +msgstr "Vie…" msgid "Export EDID" msgstr "Vie EDID" @@ -3038,3 +3002,24 @@ msgstr "Tumma" msgid "Search:" msgstr "Hae:" + +msgid "Force interpretation" +msgstr "Pakota tulkinta" + +msgid "Allow recompilation" +msgstr "Salli uudelleenkääntäminen" + +msgid "&Force interpretation" +msgstr "&Pakota tulkinta" + +msgid "&Allow recompilation" +msgstr "&Salli uudelleenkääntäminen" + +msgid "&Fast forward" +msgstr "" + +msgid "Fast forward" +msgstr "" + +msgid "To change the system directory, stop all running machines." +msgstr "" diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po index d51553ba6f8..2e1422a08cd 100644 --- a/src/qt/languages/fr-FR.po +++ b/src/qt/languages/fr-FR.po @@ -1,7 +1,7 @@ msgid "" msgstr "" -"PO-Revision-Date: 2025-11-29 00:34+0000\n" -"Last-Translator: OBattler \n" +"PO-Revision-Date: 2025-12-04 18:56+0000\n" +"Last-Translator: Alexander Babikov \n" "Language-Team: French \n" "Language: fr-FR\n" "MIME-Version: 1.0\n" @@ -19,7 +19,7 @@ msgid "&Keyboard requires capture" msgstr "C&apturer le clavier" msgid "&Right CTRL is left ALT" -msgstr "CTRL &Droite devient ALT Gauche" +msgstr "CTRL &droite devient ALT gauche" msgid "&Hard reset" msgstr "&Hard reset" @@ -28,7 +28,7 @@ msgid "&Ctrl+Alt+Del" msgstr "&Ctrl+Alt+Suppr" msgid "Ctrl+Alt+&Esc" -msgstr "Ctrl+Alt+&Esc" +msgstr "Ctrl+A<+Échap" msgid "&Pause" msgstr "&Pause" @@ -55,10 +55,10 @@ msgid "&Resizeable window" msgstr "Fenêtre &redimensionnable" msgid "R&emember size && position" -msgstr "S&auvegarder taille && position" +msgstr "S&auvegarder taille et position" msgid "Remember size && position" -msgstr "Sauvegarder taille && position" +msgstr "Sauvegarder taille et position" msgid "Re&nderer" msgstr "Moteur de re&ndu vidéo" @@ -72,14 +72,14 @@ msgstr "Open&GL (3.0 Core)" msgid "&VNC" msgstr "&VNC" -msgid "Specify &dimensions..." -msgstr "Spécifier dimen&sions..." +msgid "Specify &dimensions…" +msgstr "Spécifier dimen&sions…" msgid "Force &4:3 display ratio" msgstr "Forcer le ratio &4:3" msgid "&Window scale factor" -msgstr "Facteur d'&Echelle" +msgstr "Facteur d'éch&elle" msgid "&0.5x" msgstr "&0.5x" @@ -112,7 +112,7 @@ msgid "&8x" msgstr "&8x" msgid "Fi<er method" -msgstr "Mét&hode de Filtre" +msgstr "Mét&hode de filtre" msgid "&Nearest" msgstr "&Plus proche" @@ -139,16 +139,16 @@ msgid "&Square pixels (Keep ratio)" msgstr "Pixels &carrés (Conserver le ratio)" msgid "&Integer scale" -msgstr "&Echelle entière" +msgstr "Éch&elle entière" msgid "4:&3 Integer scale" -msgstr "Echelle entière 4:&3" +msgstr "Échelle entière 4:&3" msgid "EGA/(S)&VGA settings" msgstr "Réglages EGA/(S)&VGA" msgid "&Inverted VGA monitor" -msgstr "Moniteur VGA &Inversé" +msgstr "Moniteur VGA &inversé" msgid "VGA screen &type" msgstr "&Type d'écran VGA" @@ -160,22 +160,22 @@ msgid "RGB (no brown)" msgstr "RVB (sans brun)" msgid "&RGB Grayscale" -msgstr "Niveau de Gris &RVB" +msgstr "Niveau de gris &RVB" msgid "Generic RGBI color monitor" msgstr "Moniteur couleur RVB générique" msgid "&Amber monitor" -msgstr "Moniteur &Ambre" +msgstr "Moniteur &ambre" msgid "&Green monitor" -msgstr "Moniteur &Vert" +msgstr "Moniteur &vert" msgid "&White monitor" -msgstr "Moniteur &Blanc" +msgstr "Moniteur &blanc" msgid "Grayscale &conversion type" -msgstr "Type de &conversion du niveau de Gris" +msgstr "Type de &conversion du niveau de gris" msgid "BT&601 (NTSC/PAL)" msgstr "BT&601 (NTSC/PAL)" @@ -198,29 +198,50 @@ msgstr "&Média" msgid "&Tools" msgstr "Ou&tils" -msgid "&Settings..." -msgstr "&Réglages..." +msgid "&Settings…" +msgstr "&Réglages…" -msgid "Settings..." -msgstr "Réglages..." +msgid "Settings…" +msgstr "Réglages…" msgid "&Update status bar icons" msgstr "Mettre à jour la barre de stat&us" msgid "Take s&creenshot" -msgstr "Copie d'é&cran" +msgstr "Faire copie d'é&cran" + +msgid "Take screenshot" +msgstr "Faire copie d'écran" + +msgid "Take &raw screenshot" +msgstr "Faire copie &brute d'écran" + +msgid "Take raw screenshot" +msgstr "Faire copie brute d'écran" + +msgid "C&opy screenshot" +msgstr "C&opier copie d'écran" + +msgid "Copy screenshot" +msgstr "Copier copie d'écran" + +msgid "Copy r&aw screenshot" +msgstr "Copier copie b&rute d'écran" + +msgid "Copy raw screenshot" +msgstr "Copier copie brute d'écran" msgid "S&ound" msgstr "S&on" -msgid "&Preferences..." -msgstr "&Préférences..." +msgid "&Preferences…" +msgstr "&Préférences…" msgid "Enable &Discord integration" msgstr "Activer l'intégration &Discord" -msgid "Sound &gain..." -msgstr "&Gain Son..." +msgid "Sound &gain…" +msgstr "&Gain son…" msgid "Begin trace" msgstr "Démarrer traces" @@ -231,20 +252,20 @@ msgstr "Arrêter traces" msgid "&Help" msgstr "Ai&de" -msgid "&Documentation..." -msgstr "&Documentation..." +msgid "&Documentation…" +msgstr "&Documentation…" -msgid "&About 86Box..." -msgstr "&A Propos de 86Box..." +msgid "&About 86Box…" +msgstr "À &propos de 86Box…" -msgid "&New image..." -msgstr "&Nouvelle image..." +msgid "&New image…" +msgstr "&Nouvelle image…" -msgid "&Existing image..." -msgstr "Image &Existante..." +msgid "&Existing image…" +msgstr "Image &existante…" -msgid "Existing image (&Write-protected)..." -msgstr "Image Existante (&Lecture seule)..." +msgid "Existing image (&Write-protected)…" +msgstr "Image existante (&Lecture seule)…" msgid "&Record" msgstr "En®istrer" @@ -256,16 +277,16 @@ msgid "&Rewind to the beginning" msgstr "&Revenir au debut" msgid "&Fast forward to the end" -msgstr "Avance rapide jusqu'à la &Fin" +msgstr "Avance rapide jusqu'à la &fin" msgid "E&ject" msgstr "É&jecter" -msgid "&Image..." -msgstr "&Image..." +msgid "&Image…" +msgstr "&Image…" -msgid "E&xport to 86F..." -msgstr "E&xport vers 86F..." +msgid "E&xport to 86F…" +msgstr "E&xport vers 86F…" msgid "&Mute" msgstr "&Couper" @@ -276,8 +297,8 @@ msgstr "V&ide" msgid "Reload previous image" msgstr "Recharger image précedente" -msgid "&Folder..." -msgstr "&Dossier..." +msgid "&Folder…" +msgstr "&Dossier…" msgid "Preferences" msgstr "Préférences" @@ -423,17 +444,17 @@ msgstr "Manette :" msgid "Joystick" msgstr "Manette" -msgid "Joystick 1..." -msgstr "Manette 1..." +msgid "Joystick 1…" +msgstr "Manette 1…" -msgid "Joystick 2..." -msgstr "Manette 2..." +msgid "Joystick 2…" +msgstr "Manette 2…" -msgid "Joystick 3..." -msgstr "Manette 3..." +msgid "Joystick 3…" +msgstr "Manette 3…" -msgid "Joystick 4..." -msgstr "Manette 4..." +msgid "Joystick 4…" +msgstr "Manette 4…" msgid "Sound card #1:" msgstr "Carte son 1 :" @@ -522,10 +543,10 @@ msgstr "Port parallèle 3" msgid "Parallel port 4" msgstr "Port parallèle 4" -msgid "FD Controller:" -msgstr "Contrôleur FD :" +msgid "Floppy disk controller:" +msgstr "Contrôleur de disquette :" -msgid "CD-ROM Controller:" +msgid "CD-ROM controller:" msgstr "Contrôleur CD-ROM :" msgid "Tertiary IDE Controller" @@ -534,11 +555,11 @@ msgstr "Troisième contrôleur IDE" msgid "Quaternary IDE Controller" msgstr "Quatrième contrôleur IDE" -msgid "Hard disk" -msgstr "Disque dur" +msgid "Hard disk controllers" +msgstr "Contrôleurs de disque dur" -msgid "SCSI" -msgstr "SCSI" +msgid "SCSI controllers" +msgstr "Contrôleurs SCSI" msgid "Controller 1:" msgstr "Contrôleur 1 :" @@ -561,11 +582,11 @@ msgstr "Disques durs :" msgid "Firmware Version" msgstr "Version du micrologiciel" -msgid "&New..." -msgstr "&Nouveau..." +msgid "&New…" +msgstr "&Nouveau…" -msgid "&Existing..." -msgstr "&Existant..." +msgid "&Existing…" +msgstr "&Existant…" msgid "&Remove" msgstr "&Supprimer" @@ -595,7 +616,7 @@ msgid "Type:" msgstr "Type :" msgid "Image Format:" -msgstr "Format Image :" +msgstr "Format image :" msgid "Block Size:" msgstr "Taille du bloc :" @@ -682,7 +703,7 @@ msgid "&Removable disk %1 (%2): %3" msgstr "&Disque amovible %1 (%2) : %3" msgid "Removable disk images" -msgstr "Imges de disque amovible" +msgstr "Images de disque amovible" msgid "Image %1" msgstr "Image %1" @@ -873,9 +894,6 @@ msgstr "Manette de jeu à 4 boutons" msgid "6-button gamepad" msgstr "Manette de jeu à 6 boutons" -msgid "Gravis PC GamePad" -msgstr "Gravis PC GamePad" - msgid "2-button flight yoke" msgstr "Manette de vol à 2 boutons" @@ -903,51 +921,6 @@ msgstr "Volant (3 axes, 3 boutons)" msgid "Steering wheel (3-axis, 4-button)" msgstr "Volant (3 axes, 4 boutons)" -msgid "CH Flightstick" -msgstr "CH Flightstick" - -msgid "CH Flightstick + CH Pedals" -msgstr "CH Flightstick + CH Pedals" - -msgid "CH Flightstick + CH Pedals Pro" -msgstr "CH Flightstick + CH Pedals Pro" - -msgid "CH Flightstick Pro" -msgstr "CH Flightstick Pro" - -msgid "CH Flightstick Pro + CH Pedals" -msgstr "CH Flightstick Pro + CH Pedals" - -msgid "CH Flightstick Pro + CH Pedals Pro" -msgstr "CH Flightstick Pro + CH Pedals Pro" - -msgid "CH Virtual Pilot" -msgstr "CH Virtual Pilot" - -msgid "CH Virtual Pilot + CH Pedals" -msgstr "CH Virtual Pilot + CH Pedals" - -msgid "CH Virtual Pilot + CH Pedals Pro" -msgstr "CH Virtual Pilot + CH Pedals Pro" - -msgid "CH Virtual Pilot Pro" -msgstr "CH Virtual Pilot Pro" - -msgid "CH Virtual Pilot Pro + CH Pedals" -msgstr "CH Virtual Pilot Pro + CH Pedals" - -msgid "CH Virtual Pilot Pro + CH Pedals Pro" -msgstr "CH Virtual Pilot Pro + CH Pedals Pro" - -msgid "Microsoft SideWinder Pad" -msgstr "Microsoft SideWinder Pad" - -msgid "Thrustmaster Flight Control System" -msgstr "Système de contrôle de vol Thrustmaster" - -msgid "Thrustmaster FCS + Rudder Control System" -msgstr "SCV Thrustmaster + Système de commande de gouvernail" - msgid "Thrustmaster Formula T1/T2 with adapter" msgstr "Thrustmaster Formula T1/T2 avec adaptateur" @@ -970,7 +943,7 @@ msgid "Advanced sector images" msgstr "Images secteur avancé" msgid "Flux images" -msgstr "Images Flux" +msgstr "Images de flux" msgid "Are you sure you want to hard reset the emulated machine?" msgstr "Etes-vous sûr de vouloir réinitialiser la machine émulée ?" @@ -1002,11 +975,17 @@ msgstr "Dispositif interne" msgid "&File" msgstr "&Fichier" -msgid "&New machine..." -msgstr "&Nouvelle machine..." +msgid "&New machine…" +msgstr "&Nouvelle machine…" + +msgid "New machine…" +msgstr "Nouvelle machine…" + +msgid "New machine" +msgstr "Nouvelle machine" -msgid "&Check for updates..." -msgstr "&Vérifier les mises à jour..." +msgid "&Check for updates…" +msgstr "&Vérifier les mises à jour…" msgid "Exit" msgstr "Sortir" @@ -1176,8 +1155,8 @@ msgstr "Impossible d'ouvrir le fichier de configuration sélectionné pour lectu msgid "Use regular expressions in search box" msgstr "Utilisez des expressions régulières dans le champ de recherche" -msgid "%1 machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" -msgstr "%1 machine(s) sont actuellement actives. Êtes-vous sûr de vouloir quitter le gestionnaire de machines virtuelles malgré tout ?" +msgid "%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" +msgstr "%n machine(s) sont actuellement actives. Êtes-vous sûr de vouloir quitter le gestionnaire de machines virtuelles malgré tout ?" msgid "Add new system wizard" msgstr "Assistant pour ajouter un nouveau système" @@ -1257,26 +1236,23 @@ msgstr "Définir le nom d'affichage" msgid "Enter the new display name (blank to reset)" msgstr "Entrez le nouveau nom d'affichage (laissez vide pour réinitialiser)" -msgid "Change &display name..." -msgstr "Modifier le nom &d'affichage..." +msgid "Change &display name…" +msgstr "Modifier le nom &d'affichage…" -msgid "Context Menu" -msgstr "Menu contextuel" +msgid "&Open folder…" +msgstr "&Ouvrir le dossier…" -msgid "&Open folder..." -msgstr "&Ouvrir le dossier..." +msgid "Open p&rinter tray…" +msgstr "Ouvrez le bac de l'&imprimante…" -msgid "Open p&rinter tray..." -msgstr "Ouvrez le bac de l'&imprimante..." - -msgid "Set &icon..." -msgstr "Définir l'&icône..." +msgid "Set &icon…" +msgstr "Définir l'&icône…" msgid "Select an icon" msgstr "Sélectionnez une icône" -msgid "C&lone..." -msgstr "C&loner..." +msgid "C&lone…" +msgstr "C&loner…" msgid "Virtual machine \"%1\" (%2) will be cloned into:" msgstr "La machine virtuelle « %1 » (%2) sera clonée dans :" @@ -1342,7 +1318,7 @@ msgid "Warning" msgstr "Avertissement" msgid "&Kill" -msgstr "Fo&rcer Extinction" +msgstr "Fo&rcer extinction" msgid "Killing a virtual machine can cause data loss. Only do this if the 86Box process gets stuck.\n\nDo you really wish to kill the virtual machine \"%1\"?" msgstr "La fermeture forcée d'une machine virtuelle peut entraîner une perte de données. Ne procédez ainsi que si le processus 86Box est bloqué.\n\nVoulez-vous vraiment fermer la machine virtuelle « %1 » ?" @@ -1362,8 +1338,8 @@ msgstr "Pas de capture d'écran" msgid "Search" msgstr "Rechercher" -msgid "Searching for VMs..." -msgstr "Recherche de machines virtuelles..." +msgid "Searching for VMs…" +msgstr "Recherche de machines virtuelles…" msgid "Found %1" msgstr "Trouvé %1" @@ -1398,11 +1374,11 @@ msgstr "Disque dur (%1)" msgid "MFM/RLL or ESDI CD-ROM drives never existed" msgstr "Les lecteurs de CD-ROM MFM/RLL ou ESDI n'ont jamais existé" -msgid "Custom..." -msgstr "Personnalisé..." +msgid "Custom…" +msgstr "Personnalisé…" -msgid "Custom (large)..." -msgstr "Personnalisé (grand)..." +msgid "Custom (large)…" +msgstr "Personnalisé (grand)…" msgid "Add New Hard Disk" msgstr "Ajouter un nouveau disque dur" @@ -1501,10 +1477,10 @@ msgid "Differencing VHD (.vhd)" msgstr "VHD différentiel (.vhd)" msgid "Large blocks (2 MB)" -msgstr "Grands Blocs (2 Mo)" +msgstr "Grands blocs (2 Mo)" msgid "Small blocks (512 KB)" -msgstr "Petits Blocs (512 Ko)" +msgstr "Petits blocs (512 Ko)" msgid "VHD files" msgstr "Fichiers VHD" @@ -1521,21 +1497,6 @@ msgstr "Les horodatages des disques parents et enfants ne correspondent pas" msgid "Could not fix VHD timestamp." msgstr "Impossible de réparer l'horodatage du VHD." -msgid "MFM/RLL" -msgstr "MFM/RLL" - -msgid "XTA" -msgstr "XTA" - -msgid "ESDI" -msgstr "ESDI" - -msgid "IDE" -msgstr "IDE" - -msgid "ATAPI" -msgstr "ATAPI" - msgid "CD-ROM %1 (%2): %3" msgstr "CD-ROM %1 (%2) : %3" @@ -1681,19 +1642,19 @@ msgid "List of MCA devices:" msgstr "Liste des dispositifs MCA :" msgid "&Tablet tool" -msgstr "Outil Tablette" +msgstr "Outil tablette" msgid "About &Qt" -msgstr "A propos de &Qt" +msgstr "À propos de &Qt" -msgid "&MCA devices..." -msgstr "Dispositifs MCA..." +msgid "&MCA devices…" +msgstr "Dispositifs MCA…" msgid "Show non-&primary monitors" msgstr "Afficher les moniteurs non pr&imaires" -msgid "Open screenshots &folder..." -msgstr "Ouvrir le do&ssier des captures d'écran..." +msgid "Open screenshots &folder…" +msgstr "Ouvrir le do&ssier des captures d'écran…" msgid "Appl&y fullscreen stretch mode when maximized" msgstr "Appli&quer le mode élargi plein écran lorsque la fenêtre est maximisée" @@ -1713,8 +1674,8 @@ msgstr "&Connecté" msgid "Clear image &history" msgstr "Effacer l'&historique de l'image" -msgid "Create..." -msgstr "Créer..." +msgid "Create…" +msgstr "Créer…" msgid "Host CD/DVD Drive (%1)" msgstr "Lecteur CD/DVD hôte (%1)" @@ -1741,7 +1702,7 @@ msgid "Use target framerate:" msgstr "Utiliser le taux de rafraîchissement cible :" msgid " fps" -msgstr " Images par seconde" +msgstr " images par seconde" msgid "VSync" msgstr "VSync" @@ -1755,8 +1716,8 @@ msgstr "Shaders" msgid "Remove" msgstr "Retirer" -msgid "Browse..." -msgstr "Parcourir..." +msgid "Browse…" +msgstr "Parcourir…" msgid "Couldn't create OpenGL context." msgstr "Impossible de créer un contexte OpenGL." @@ -1845,8 +1806,8 @@ msgstr "Transfert du port série 3" msgid "Serial port passthrough 4" msgstr "Transfert du port série 4" -msgid "Renderer &options..." -msgstr "&Options du rendu..." +msgid "Renderer &options…" +msgstr "&Options du rendu…" msgid "PC/XT Keyboard" msgstr "Clavier PC/XT" @@ -1899,8 +1860,8 @@ msgstr "3M MicroTouch (série)" msgid "Default Baud rate" msgstr "Vitesse de transmission par défaut" -msgid "[COM] Standard Hayes-compliant Modem" -msgstr "[COM] Modem standard conforme à la norme Hayes" +msgid "Standard Hayes-compliant Modem" +msgstr "Modem standard conforme à la norme Hayes" msgid "Roland MT-32 Emulation" msgstr "Émulation Roland MT-32" @@ -1983,6 +1944,9 @@ msgstr "IRQ du port série" msgid "Parallel port IRQ" msgstr "IRQ du port parallèle" +msgid "Hard disk" +msgstr "Disque dur" + msgid "BIOS Revision" msgstr "Révision du BIOS" @@ -2002,7 +1966,7 @@ msgid "Translate 26 -> 17" msgstr "Traduire 26 -> 17" msgid "Language" -msgstr "Langage" +msgstr "Langue" msgid "Enable backlight" msgstr "Activer le rétro-éclairage" @@ -2058,9 +2022,6 @@ msgstr "Transfert MIDI" msgid "MIDI Clockout" msgstr "Horloge MIDI" -msgid "SoundFont" -msgstr "SoundFont" - msgid "Output Gain" msgstr "Gain sortie" @@ -2710,28 +2671,28 @@ msgid "High performance impact" msgstr "Impact important sur la performance" msgid "[Generic] RAM Disk (max. speed)" -msgstr "[Generic] Disque RAM (vitesse maximale)" +msgstr "[Générique] Disque RAM (vitesse maximale)" msgid "[Generic] 1989 (3500 RPM)" -msgstr "[Generic] 1989 (3500 RPM)" +msgstr "[Générique] 1989 (3500 RPM)" msgid "[Generic] 1992 (3600 RPM)" -msgstr "[Generic] 1992 (3600 RPM)" +msgstr "[Générique] 1992 (3600 RPM)" msgid "[Generic] 1994 (4500 RPM)" -msgstr "[Generic] 1994 (4500 RPM)" +msgstr "[Générique] 1994 (4500 RPM)" msgid "[Generic] 1996 (5400 RPM)" -msgstr "[Generic] 1996 (5400 RPM)" +msgstr "[Générique] 1996 (5400 RPM)" msgid "[Generic] 1997 (5400 RPM)" -msgstr "[Generic] 1997 (5400 RPM)" +msgstr "[Générique] 1997 (5400 RPM)" msgid "[Generic] 1998 (5400 RPM)" -msgstr "[Generic] 1998 (5400 RPM)" +msgstr "[Générique] 1998 (5400 RPM)" msgid "[Generic] 2000 (7200 RPM)" -msgstr "[Generic] 2000 (7200 RPM)" +msgstr "[Générique] 2000 (7200 RPM)" msgid "IBM 8514/A clone (ISA)" msgstr "Clone IBM 8514/A (ISA)" @@ -2764,7 +2725,7 @@ msgid "Ask for confirmation before saving settings" msgstr "Demander confirmation avant de sauvegarder les réglages" msgid "Ask for confirmation before hard resetting" -msgstr "Demander confirmation avant Hard Reset" +msgstr "Demander confirmation avant hard reset" msgid "Ask for confirmation before quitting" msgstr "Demander confirmation avant de quitter" @@ -2776,7 +2737,7 @@ msgid "Model" msgstr "Modèle" msgid "Model:" -msgstr "Modèle:" +msgstr "Modèle :" msgid "Failed to initialize Vulkan renderer." msgstr "Impossible d’initialiser le moteur de rendu Vulkan." @@ -2800,7 +2761,7 @@ msgid "Shader Manager" msgstr "Gestionnaire de shader" msgid "Shader Configuration" -msgstr "Configuration Shader" +msgstr "Configuration du shader" msgid "Add" msgstr "Ajouter" @@ -2853,9 +2814,6 @@ msgstr "Activer/désactiver le mode plein écran" msgid "Toggle UI in fullscreen" msgstr "Basculer l'interface utilisateur en mode plein écran" -msgid "Screenshot" -msgstr "Capture d'écran" - msgid "Release mouse pointer" msgstr "Relâcher le pointeur de la souris" @@ -2959,7 +2917,7 @@ msgid "You are currently running build %1." msgstr "Vous exécutez actuellement le build %1." msgid "Build %1 is now available." -msgstr "Le Build %1 est désormais disponible." +msgstr "Le build %1 est désormais disponible." msgid "Would you like to visit the download page?" msgstr "Souhaitez-vous visiter la page de téléchargement ?" @@ -2970,8 +2928,8 @@ msgstr "Visiter la page de téléchargement" msgid "Update check" msgstr "Vérification des mises à jour" -msgid "Checking for updates..." -msgstr "Recherche de mises à jour..." +msgid "Checking for updates…" +msgstr "Recherche de mises à jour…" msgid "86Box Update" msgstr "Mise à jour de 86Box" @@ -3009,8 +2967,8 @@ msgstr "Luminosité" msgid "Sharpness" msgstr "Netteté" -msgid "&CGA composite settings..." -msgstr "Réglages du mode composite &CGA..." +msgid "&CGA composite settings…" +msgstr "Réglages du mode composite &CGA…" msgid "CGA composite settings" msgstr "Réglages du mode composite CGA" @@ -3018,8 +2976,8 @@ msgstr "Réglages du mode composite CGA" msgid "Monitor EDID" msgstr "Écran EDID" -msgid "Export..." -msgstr "Exporter..." +msgid "Export…" +msgstr "Exporter…" msgid "Export EDID" msgstr "Exporter l'EDID" @@ -3044,3 +3002,24 @@ msgstr "Sombre" msgid "Search:" msgstr "Rechercher :" + +msgid "Force interpretation" +msgstr "Forcer l'interprétation" + +msgid "Allow recompilation" +msgstr "Permettre la recompilation" + +msgid "&Force interpretation" +msgstr "&Forcer l'interprétation" + +msgid "&Allow recompilation" +msgstr "&Permettre la recompilation" + +msgid "&Fast forward" +msgstr "" + +msgid "Fast forward" +msgstr "" + +msgid "To change the system directory, stop all running machines." +msgstr "" diff --git a/src/qt/languages/hr-HR.po b/src/qt/languages/hr-HR.po index ee6c238b9b6..b3d9a68f188 100644 --- a/src/qt/languages/hr-HR.po +++ b/src/qt/languages/hr-HR.po @@ -74,8 +74,8 @@ msgstr "Open&GL (3.0 jezgra)" msgid "&VNC" msgstr "&VNC" -msgid "Specify &dimensions..." -msgstr "Odrediti veličinu..." +msgid "Specify &dimensions…" +msgstr "Odrediti veličinu…" msgid "Force &4:3 display ratio" msgstr "&4:3 omjer prikaza" @@ -200,11 +200,11 @@ msgstr "&Mediji" msgid "&Tools" msgstr "&Alati" -msgid "&Settings..." -msgstr "&Opcije..." +msgid "&Settings…" +msgstr "&Opcije…" -msgid "Settings..." -msgstr "Opcije..." +msgid "Settings…" +msgstr "Opcije…" msgid "&Update status bar icons" msgstr "&Ažuriraj ikone statusnog redka" @@ -212,17 +212,38 @@ msgstr "&Ažuriraj ikone statusnog redka" msgid "Take s&creenshot" msgstr "Napravi &snimku zaslona" +msgid "Take screenshot" +msgstr "Napravi snimku zaslona" + +msgid "Take &raw screenshot" +msgstr "Napravi &neobrađenu snimku zaslona" + +msgid "Take raw screenshot" +msgstr "Napravi neobrađenu snimku zaslona" + +msgid "C&opy screenshot" +msgstr "K&opiraj snimku zaslona" + +msgid "Copy screenshot" +msgstr "Kopiraj snimku zaslona" + +msgid "Copy r&aw screenshot" +msgstr "Kopiraj n&eobrađenu snimku zaslona" + +msgid "Copy raw screenshot" +msgstr "Kopiraj neobrađenu snimku zaslona" + msgid "S&ound" msgstr "&Zvuk" -msgid "&Preferences..." -msgstr "&Postavke..." +msgid "&Preferences…" +msgstr "&Postavke…" msgid "Enable &Discord integration" msgstr "Omogući integraciju sa programom &Discord" -msgid "Sound &gain..." -msgstr "&Pojačavanje zvuka..." +msgid "Sound &gain…" +msgstr "&Pojačavanje zvuka…" msgid "Begin trace" msgstr "Z&apočni praćenje" @@ -233,20 +254,20 @@ msgstr "&Svrši praćenje" msgid "&Help" msgstr "P&omoć" -msgid "&Documentation..." -msgstr "&Dokumentacija..." +msgid "&Documentation…" +msgstr "&Dokumentacija…" -msgid "&About 86Box..." -msgstr "&O programu 86Box..." +msgid "&About 86Box…" +msgstr "&O programu 86Box…" -msgid "&New image..." -msgstr "&Nova slika..." +msgid "&New image…" +msgstr "&Nova slika…" -msgid "&Existing image..." -msgstr "&Postojeća slika..." +msgid "&Existing image…" +msgstr "&Postojeća slika…" -msgid "Existing image (&Write-protected)..." -msgstr "Postojeća slika (&zaštićena od pisanja)..." +msgid "Existing image (&Write-protected)…" +msgstr "Postojeća slika (&zaštićena od pisanja)…" msgid "&Record" msgstr "&Snimi" @@ -263,11 +284,11 @@ msgstr "&Preskoči do kraja" msgid "E&ject" msgstr "&Izbaci" -msgid "&Image..." -msgstr "&Slika..." +msgid "&Image…" +msgstr "&Slika…" -msgid "E&xport to 86F..." -msgstr "&Izvozi u 86F..." +msgid "E&xport to 86F…" +msgstr "&Izvozi u 86F…" msgid "&Mute" msgstr "&Isključi zvuk" @@ -278,8 +299,8 @@ msgstr "&Prazno" msgid "Reload previous image" msgstr "Ponovo učitaj prethodnu sliku" -msgid "&Folder..." -msgstr "&Mapa..." +msgid "&Folder…" +msgstr "&Mapa…" msgid "Preferences" msgstr "Postavke" @@ -425,17 +446,17 @@ msgstr "Palica za igru:" msgid "Joystick" msgstr "Palica za igru" -msgid "Joystick 1..." -msgstr "Palica za igru 1..." +msgid "Joystick 1…" +msgstr "Palica za igru 1…" -msgid "Joystick 2..." -msgstr "Palica za igru 2..." +msgid "Joystick 2…" +msgstr "Palica za igru 2…" -msgid "Joystick 3..." -msgstr "Palica za igru 3..." +msgid "Joystick 3…" +msgstr "Palica za igru 3…" -msgid "Joystick 4..." -msgstr "Palica za igru 4..." +msgid "Joystick 4…" +msgstr "Palica za igru 4…" msgid "Sound card #1:" msgstr "Zvučna kartica 1:" @@ -524,10 +545,10 @@ msgstr "Paralelna vrata 3" msgid "Parallel port 4" msgstr "Paralelna vrata 4" -msgid "FD Controller:" +msgid "Floppy disk controller:" msgstr "Kontroler diskete:" -msgid "CD-ROM Controller:" +msgid "CD-ROM controller:" msgstr "Kontroler CD-ROM:" msgid "Tertiary IDE Controller" @@ -536,11 +557,11 @@ msgstr "Tercijarni IDE kontroler" msgid "Quaternary IDE Controller" msgstr "Kvaternarni IDE kontroler" -msgid "Hard disk" -msgstr "Tvrdi disk" +msgid "Hard disk controllers" +msgstr "Kontroleri tvrdih diskova" -msgid "SCSI" -msgstr "SCSI" +msgid "SCSI controllers" +msgstr "Kontroleri SCSI" msgid "Controller 1:" msgstr "Kontroler 1:" @@ -563,11 +584,11 @@ msgstr "Tvrdi diskovi:" msgid "Firmware Version" msgstr "Verzija firmvera" -msgid "&New..." -msgstr "&Novi..." +msgid "&New…" +msgstr "&Novi…" -msgid "&Existing..." -msgstr "&Postojeći..." +msgid "&Existing…" +msgstr "&Postojeći…" msgid "&Remove" msgstr "&Ukloni" @@ -875,9 +896,6 @@ msgstr "Gamepad s 4 tipke" msgid "6-button gamepad" msgstr "Gamepad s 6 tipke" -msgid "Gravis PC GamePad" -msgstr "Gravis PC GamePad" - msgid "2-button flight yoke" msgstr "Jaram za letenje s 2 tipke" @@ -905,51 +923,6 @@ msgstr "Volan (3 osi, 3 tipke)" msgid "Steering wheel (3-axis, 4-button)" msgstr "Volan (3 osi, 4 tipke)" -msgid "CH Flightstick" -msgstr "CH Flightstick" - -msgid "CH Flightstick + CH Pedals" -msgstr "CH Flightstick + CH Pedals" - -msgid "CH Flightstick + CH Pedals Pro" -msgstr "CH Flightstick + CH Pedals Pro" - -msgid "CH Flightstick Pro" -msgstr "CH Flightstick Pro" - -msgid "CH Flightstick Pro + CH Pedals" -msgstr "CH Flightstick Pro + CH Pedals" - -msgid "CH Flightstick Pro + CH Pedals Pro" -msgstr "CH Flightstick Pro + CH Pedals Pro" - -msgid "CH Virtual Pilot" -msgstr "CH Virtual Pilot" - -msgid "CH Virtual Pilot + CH Pedals" -msgstr "CH Virtual Pilot + CH Pedals" - -msgid "CH Virtual Pilot + CH Pedals Pro" -msgstr "CH Virtual Pilot + CH Pedals Pro" - -msgid "CH Virtual Pilot Pro" -msgstr "CH Virtual Pilot Pro" - -msgid "CH Virtual Pilot Pro + CH Pedals" -msgstr "CH Virtual Pilot Pro + CH Pedals" - -msgid "CH Virtual Pilot Pro + CH Pedals Pro" -msgstr "CH Virtual Pilot Pro + CH Pedals Pro" - -msgid "Microsoft SideWinder Pad" -msgstr "Microsoft SideWinder Pad" - -msgid "Thrustmaster Flight Control System" -msgstr "Thrustmaster Flight Control System" - -msgid "Thrustmaster FCS + Rudder Control System" -msgstr "Thrustmaster FCS + Rudder Control System" - msgid "Thrustmaster Formula T1/T2 with adapter" msgstr "Thrustmaster Formula T1/T2 s adapterom" @@ -1004,11 +977,17 @@ msgstr "Uunutarnji uređaj" msgid "&File" msgstr "&Datoteka" -msgid "&New machine..." -msgstr "&Novi sistem..." +msgid "&New machine…" +msgstr "&Novi sistem…" + +msgid "New machine…" +msgstr "Novi sistem…" + +msgid "New machine" +msgstr "Novi sistem" -msgid "&Check for updates..." -msgstr "&Provjeri ažuriranja..." +msgid "&Check for updates…" +msgstr "&Provjeri ažuriranja…" msgid "Exit" msgstr "Izlazi" @@ -1178,8 +1157,8 @@ msgstr "Nije moguće otvoriti odabranu konfiguracijsku datoteku za čitanje: %1" msgid "Use regular expressions in search box" msgstr "U polju za pretraživanje koristite regularne izraze" -msgid "%1 machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" -msgstr "Broj trenutno aktivnih računala je %1. Jeste li sigurni da ipak želite izaći iz upravitelja virtualnih sistema?" +msgid "%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" +msgstr "Broj trenutno aktivnih računala je %n. Jeste li sigurni da ipak želite izaći iz upravitelja virtualnih sistema?" msgid "Add new system wizard" msgstr "Čarobnjak za dodavanje novog sistema" @@ -1259,26 +1238,23 @@ msgstr "Postavi prikazno ime" msgid "Enter the new display name (blank to reset)" msgstr "Unesite novo prikazno ime (prazno za ponovo postaviti)" -msgid "Change &display name..." -msgstr "Promijeni &prikazno ime..." +msgid "Change &display name…" +msgstr "Promijeni &prikazno ime…" -msgid "Context Menu" -msgstr "Kontekstni izbornik" +msgid "&Open folder…" +msgstr "&Otvori mapu…" -msgid "&Open folder..." -msgstr "&Otvori mapu..." +msgid "Open p&rinter tray…" +msgstr "Otvori ladicu &pisača…" -msgid "Open p&rinter tray..." -msgstr "Otvori ladicu &pisača..." - -msgid "Set &icon..." -msgstr "Postavi &ikonu..." +msgid "Set &icon…" +msgstr "Postavi &ikonu…" msgid "Select an icon" msgstr "Odaberite ikonu" -msgid "C&lone..." -msgstr "K&loniraj..." +msgid "C&lone…" +msgstr "K&loniraj…" msgid "Virtual machine \"%1\" (%2) will be cloned into:" msgstr "Virtualni sistem \"%1\" (%2) bit će kloniran u:" @@ -1364,8 +1340,8 @@ msgstr "Nema snimke zaslona" msgid "Search" msgstr "Pretraživanje" -msgid "Searching for VMs..." -msgstr "Traženje virtualnih sistema..." +msgid "Searching for VMs…" +msgstr "Traženje virtualnih sistema…" msgid "Found %1" msgstr "Pronađeno %1" @@ -1400,11 +1376,11 @@ msgstr "Tvrdi disk (%1)" msgid "MFM/RLL or ESDI CD-ROM drives never existed" msgstr "MFM/RLL ili ESDI CD-ROM pogoni nisu nikada postojali" -msgid "Custom..." -msgstr "Prilagođeno..." +msgid "Custom…" +msgstr "Prilagođeno…" -msgid "Custom (large)..." -msgstr "Prilagođeno (veliko)..." +msgid "Custom (large)…" +msgstr "Prilagođeno (veliko)…" msgid "Add New Hard Disk" msgstr "Dodajte novi tvrdi disk" @@ -1523,21 +1499,6 @@ msgstr "Vremenske ozanke matične i poređenog diska ne odgovaraju" msgid "Could not fix VHD timestamp." msgstr "Ne mogu popraviti vremensku oznaku slike VHD." -msgid "MFM/RLL" -msgstr "MFM/RLL" - -msgid "XTA" -msgstr "XTA" - -msgid "ESDI" -msgstr "ESDI" - -msgid "IDE" -msgstr "IDE" - -msgid "ATAPI" -msgstr "ATAPI" - msgid "CD-ROM %1 (%2): %3" msgstr "CD-ROM %1 (%2): %3" @@ -1688,14 +1649,14 @@ msgstr "Alat za tablet" msgid "About &Qt" msgstr "O programu &Qt" -msgid "&MCA devices..." -msgstr "Uređaji MCA ..." +msgid "&MCA devices…" +msgstr "Uređaji MCA…" msgid "Show non-&primary monitors" msgstr "Prikaži neprimarne monitore" -msgid "Open screenshots &folder..." -msgstr "Otvori mapu snimaka zaslona..." +msgid "Open screenshots &folder…" +msgstr "Otvori mapu snimaka zaslona…" msgid "Appl&y fullscreen stretch mode when maximized" msgstr "Primijeni način cijelozaslonskog rastezanja u maksimiziranom načinu" @@ -1715,8 +1676,8 @@ msgstr "&Povezan" msgid "Clear image &history" msgstr "Očisti &povijest slika" -msgid "Create..." -msgstr "Stvori..." +msgid "Create…" +msgstr "Stvori…" msgid "Host CD/DVD Drive (%1)" msgstr "CD/DVD pogon nositelja (%1)" @@ -1757,8 +1718,8 @@ msgstr "Shaderi" msgid "Remove" msgstr "Ukloni" -msgid "Browse..." -msgstr "Pretraži..." +msgid "Browse…" +msgstr "Pretraži…" msgid "Couldn't create OpenGL context." msgstr "Nije moguće stvoriti kontekst OpenGL." @@ -1847,8 +1808,8 @@ msgstr "Prolaz serijskih vrata 3" msgid "Serial port passthrough 4" msgstr "Prolaz serijskih vrata 4" -msgid "Renderer &options..." -msgstr "Opcije rendera..." +msgid "Renderer &options…" +msgstr "Opcije rendera…" msgid "PC/XT Keyboard" msgstr "Tipkovnica PC/XT" @@ -1901,8 +1862,8 @@ msgstr "3M MicroTouch (serijski)" msgid "Default Baud rate" msgstr "Zadana brzina prijenosa podataka" -msgid "[COM] Standard Hayes-compliant Modem" -msgstr "[COM] Standardni modem, usklađen s standardom Hayesom" +msgid "Standard Hayes-compliant Modem" +msgstr "Standardni modem, usklađen s standardom Hayesom" msgid "Roland MT-32 Emulation" msgstr "Emulacija Rolanda MT-32" @@ -1985,6 +1946,9 @@ msgstr "IRQ serijskih vrata" msgid "Parallel port IRQ" msgstr "IRQ paralelnih vrata" +msgid "Hard disk" +msgstr "Tvrdi disk" + msgid "BIOS Revision" msgstr "Revizija BIOS-a" @@ -2060,9 +2024,6 @@ msgstr "Prolaz ulaza MIDI" msgid "MIDI Clockout" msgstr "Taktovit MIDI" -msgid "SoundFont" -msgstr "SoundFont" - msgid "Output Gain" msgstr "Pojačavanje izlaza" @@ -2855,9 +2816,6 @@ msgstr "Uključi/isključi cijelozaslonski način" msgid "Toggle UI in fullscreen" msgstr "Prebaci korisničko sučelje u načinu cijelog zaslona" -msgid "Screenshot" -msgstr "Snimka zaslona" - msgid "Release mouse pointer" msgstr "Otpusti pokazivač miša" @@ -2972,8 +2930,8 @@ msgstr "Posjetiti stranicu za preuzimanje" msgid "Update check" msgstr "Provjera ažuriranja" -msgid "Checking for updates..." -msgstr "Provjera ažuriranja..." +msgid "Checking for updates…" +msgstr "Provjera ažuriranja…" msgid "86Box Update" msgstr "Ažuriranje programa 86Box" @@ -3011,8 +2969,8 @@ msgstr "Svjetlina" msgid "Sharpness" msgstr "Oštrina" -msgid "&CGA composite settings..." -msgstr "Opcije kompozitnog načina &CGA..." +msgid "&CGA composite settings…" +msgstr "Opcije kompozitnog načina &CGA…" msgid "CGA composite settings" msgstr "Opcije kompozitnog načina CGA" @@ -3020,8 +2978,8 @@ msgstr "Opcije kompozitnog načina CGA" msgid "Monitor EDID" msgstr "EDID monitora" -msgid "Export..." -msgstr "Izvoz..." +msgid "Export…" +msgstr "Izvoz…" msgid "Export EDID" msgstr "Izvoz EDID-a" @@ -3046,3 +3004,24 @@ msgstr "Tamno" msgid "Search:" msgstr "Pretrag:" + +msgid "Force interpretation" +msgstr "Prisilna interpretacija" + +msgid "Allow recompilation" +msgstr "Omogući rekompilaciju" + +msgid "&Force interpretation" +msgstr "&Prisilna interpretacija" + +msgid "&Allow recompilation" +msgstr "&Omogući rekompilaciju" + +msgid "&Fast forward" +msgstr "" + +msgid "Fast forward" +msgstr "" + +msgid "To change the system directory, stop all running machines." +msgstr "" diff --git a/src/qt/languages/it-IT.po b/src/qt/languages/it-IT.po index 533377b465a..f4d16bf860e 100644 --- a/src/qt/languages/it-IT.po +++ b/src/qt/languages/it-IT.po @@ -72,8 +72,8 @@ msgstr "Open&GL (3.0 Core)" msgid "&VNC" msgstr "&VNC" -msgid "Specify &dimensions..." -msgstr "Specifica dim&ensioni..." +msgid "Specify &dimensions…" +msgstr "Specifica dim&ensioni…" msgid "Force &4:3 display ratio" msgstr "Forza rapporto d'aspetto &4:3" @@ -154,13 +154,13 @@ msgid "VGA screen &type" msgstr "Schermi &VGA" msgid "RGB &Color" -msgstr "RGB a &Colori" +msgstr "RGB a &colori" msgid "RGB (no brown)" msgstr "RGB (senza marrone)" msgid "&RGB Grayscale" -msgstr "&RGB a Scala di grigi" +msgstr "&RGB a scala di grigi" msgid "Generic RGBI color monitor" msgstr "Monitor a colori RGBI generico" @@ -198,11 +198,11 @@ msgstr "&Dispositivi" msgid "&Tools" msgstr "&Strumenti" -msgid "&Settings..." -msgstr "&Impostazioni..." +msgid "&Settings…" +msgstr "&Impostazioni…" -msgid "Settings..." -msgstr "Impostazioni..." +msgid "Settings…" +msgstr "Impostazioni…" msgid "&Update status bar icons" msgstr "&Aggiorna icone della barra di stato" @@ -210,17 +210,38 @@ msgstr "&Aggiorna icone della barra di stato" msgid "Take s&creenshot" msgstr "&Cattura schermata" +msgid "Take screenshot" +msgstr "Cattura schermata" + +msgid "Take &raw screenshot" +msgstr "Cattura &grezza della schermata" + +msgid "Take raw screenshot" +msgstr "Cattura grezza della schermata" + +msgid "C&opy screenshot" +msgstr "C&opia cattura della schermata" + +msgid "Copy screenshot" +msgstr "Copia cattura della schermata" + +msgid "Copy r&aw screenshot" +msgstr "Copia cattura g&rezza della schermata" + +msgid "Copy raw screenshot" +msgstr "Copia cattura grezza della schermata" + msgid "S&ound" msgstr "A&udio" -msgid "&Preferences..." -msgstr "&Preferenze..." +msgid "&Preferences…" +msgstr "&Preferenze…" msgid "Enable &Discord integration" msgstr "Abilita integrazione &Discord" -msgid "Sound &gain..." -msgstr "Guadagno &suono..." +msgid "Sound &gain…" +msgstr "Guadagno &suono…" msgid "Begin trace" msgstr "Inizio traccia" @@ -231,20 +252,20 @@ msgstr "Fine traccia" msgid "&Help" msgstr "Ai&uto" -msgid "&Documentation..." -msgstr "&Documentazione..." +msgid "&Documentation…" +msgstr "&Documentazione…" -msgid "&About 86Box..." -msgstr "&Informazioni su 86Box..." +msgid "&About 86Box…" +msgstr "&Informazioni su 86Box…" -msgid "&New image..." -msgstr "&Nuova immagine..." +msgid "&New image…" +msgstr "&Nuova immagine…" -msgid "&Existing image..." -msgstr "&Immagine esistente..." +msgid "&Existing image…" +msgstr "&Immagine esistente…" -msgid "Existing image (&Write-protected)..." -msgstr "Immagine esistente (&protezione contro scrittura)..." +msgid "Existing image (&Write-protected)…" +msgstr "Immagine esistente (&protezione contro scrittura)…" msgid "&Record" msgstr "&Registra" @@ -261,11 +282,11 @@ msgstr "A&vanti veloce fino alla fine" msgid "E&ject" msgstr "&Espelli" -msgid "&Image..." -msgstr "&Immagine..." +msgid "&Image…" +msgstr "&Immagine…" -msgid "E&xport to 86F..." -msgstr "E&sporta in 86F..." +msgid "E&xport to 86F…" +msgstr "E&sporta in 86F…" msgid "&Mute" msgstr "&Muto" @@ -276,8 +297,8 @@ msgstr "&Espelli" msgid "Reload previous image" msgstr "Ricarica l'immagine precedente" -msgid "&Folder..." -msgstr "&Cartella..." +msgid "&Folder…" +msgstr "&Cartella…" msgid "Preferences" msgstr "Preferenze" @@ -423,17 +444,17 @@ msgstr "Joystick:" msgid "Joystick" msgstr "Joystick" -msgid "Joystick 1..." -msgstr "Joystick 1..." +msgid "Joystick 1…" +msgstr "Joystick 1…" -msgid "Joystick 2..." -msgstr "Joystick 2..." +msgid "Joystick 2…" +msgstr "Joystick 2…" -msgid "Joystick 3..." -msgstr "Joystick 3..." +msgid "Joystick 3…" +msgstr "Joystick 3…" -msgid "Joystick 4..." -msgstr "Joystick 4..." +msgid "Joystick 4…" +msgstr "Joystick 4…" msgid "Sound card #1:" msgstr "Scheda audio #1:" @@ -522,10 +543,10 @@ msgstr "Porta parallela 3" msgid "Parallel port 4" msgstr "Porta parallela 4" -msgid "FD Controller:" -msgstr "Controller FD:" +msgid "Floppy disk controller:" +msgstr "Controller del floppy disk:" -msgid "CD-ROM Controller:" +msgid "CD-ROM controller:" msgstr "Controller CD-ROM:" msgid "Tertiary IDE Controller" @@ -534,11 +555,11 @@ msgstr "Controller IDE terziario" msgid "Quaternary IDE Controller" msgstr "Controller IDE quaternario" -msgid "Hard disk" -msgstr "Disco rigido" +msgid "Hard disk controllers" +msgstr "Controller del disco rigido" -msgid "SCSI" -msgstr "SCSI" +msgid "SCSI controllers" +msgstr "Controller SCSI" msgid "Controller 1:" msgstr "Controller 1:" @@ -561,11 +582,11 @@ msgstr "Dischi rigidi:" msgid "Firmware Version" msgstr "Versione firmware" -msgid "&New..." -msgstr "&Nuovo..." +msgid "&New…" +msgstr "&Nuovo…" -msgid "&Existing..." -msgstr "&Esistente..." +msgid "&Existing…" +msgstr "&Esistente…" msgid "&Remove" msgstr "&Rimuovi" @@ -873,9 +894,6 @@ msgstr "Gamepad a 4 pulsanti" msgid "6-button gamepad" msgstr "Gamepad a 6 pulsanti" -msgid "Gravis PC GamePad" -msgstr "Gravis PC GamePad" - msgid "2-button flight yoke" msgstr "Barra di comando a 2 pulsanti" @@ -903,51 +921,6 @@ msgstr "Volante (3 assi, 3 pulsanti)" msgid "Steering wheel (3-axis, 4-button)" msgstr "Volante (3 assi, 4 pulsanti)" -msgid "CH Flightstick" -msgstr "CH Flightstick" - -msgid "CH Flightstick + CH Pedals" -msgstr "CH Flightstick + CH Pedals" - -msgid "CH Flightstick + CH Pedals Pro" -msgstr "CH Flightstick + CH Pedals Pro" - -msgid "CH Flightstick Pro" -msgstr "CH Flightstick Pro" - -msgid "CH Flightstick Pro + CH Pedals" -msgstr "CH Flightstick Pro + Pedali CH" - -msgid "CH Flightstick Pro + CH Pedals Pro" -msgstr "CH Flightstick Pro + CH Pedali Pro" - -msgid "CH Virtual Pilot" -msgstr "CH Virtual Pilot" - -msgid "CH Virtual Pilot + CH Pedals" -msgstr "CH Virtual Pilot + CH Pedali" - -msgid "CH Virtual Pilot + CH Pedals Pro" -msgstr "CH Virtual Pilot + CH Pedali Pro" - -msgid "CH Virtual Pilot Pro" -msgstr "CH Virtual Pilot Pro" - -msgid "CH Virtual Pilot Pro + CH Pedals" -msgstr "CH Virtual Pilot Pro + CH Pedali" - -msgid "CH Virtual Pilot Pro + CH Pedals Pro" -msgstr "CH Virtual Pilot Pro + CH Pedali Pro" - -msgid "Microsoft SideWinder Pad" -msgstr "Microsoft SideWinder" - -msgid "Thrustmaster Flight Control System" -msgstr "Sistema di controllo Thrustmaster Flight" - -msgid "Thrustmaster FCS + Rudder Control System" -msgstr "Thrustmaster FCS + Sistema di controllo timone" - msgid "Thrustmaster Formula T1/T2 with adapter" msgstr "Thrustmaster Formula T1/T2 con adattatore" @@ -1002,11 +975,17 @@ msgstr "Dispositivo integrato" msgid "&File" msgstr "&File" -msgid "&New machine..." -msgstr "&Nuova macchina..." +msgid "&New machine…" +msgstr "&Nuova macchina…" + +msgid "New machine…" +msgstr "Nuova macchina…" + +msgid "New machine" +msgstr "Nuova macchina" -msgid "&Check for updates..." -msgstr "&Controlla gli aggiornamenti..." +msgid "&Check for updates…" +msgstr "&Controlla gli aggiornamenti…" msgid "Exit" msgstr "Esci" @@ -1156,7 +1135,7 @@ msgid "VMs: %1" msgstr "Macchine virtuali: %1" msgid "System Directory:" -msgstr "Directory Sistema:" +msgstr "Directory sistema:" msgid "Choose directory" msgstr "Scegli la directory" @@ -1176,8 +1155,8 @@ msgstr "Impossibile aprire il file di configurazione selezionato per la lettura: msgid "Use regular expressions in search box" msgstr "Utilizza espressioni regolari nella casella di ricerca" -msgid "%1 machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" -msgstr "Sono attualmente attive %1 macchina/e. Vuoi comunque uscire dal gestore delle macchine virtuali?" +msgid "%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" +msgstr "Sono attualmente attive %n macchina/e. Vuoi comunque uscire dal gestore delle macchine virtuali?" msgid "Add new system wizard" msgstr "Procedura guidata nuovo sistema" @@ -1257,26 +1236,23 @@ msgstr "Imposta il nome da visualizzare" msgid "Enter the new display name (blank to reset)" msgstr "Inserisci il nuovo nome da visualizzare (vuoto per reimpostarlo)" -msgid "Change &display name..." -msgstr "Modifica &nome visualizzato..." +msgid "Change &display name…" +msgstr "Modifica &nome visualizzato…" -msgid "Context Menu" -msgstr "Menu contestuale" +msgid "&Open folder…" +msgstr "&Apri cartella…" -msgid "&Open folder..." -msgstr "&Apri cartella..." +msgid "Open p&rinter tray…" +msgstr "Apri vassoio &stampante…" -msgid "Open p&rinter tray..." -msgstr "Apri vassoio &stampante..." - -msgid "Set &icon..." -msgstr "Imposta &icona..." +msgid "Set &icon…" +msgstr "Imposta &icona…" msgid "Select an icon" msgstr "Seleziona un'icona" -msgid "C&lone..." -msgstr "C&lona..." +msgid "C&lone…" +msgstr "C&lona…" msgid "Virtual machine \"%1\" (%2) will be cloned into:" msgstr "La macchina virtuale \"%1\" (%2) sarà clonata in:" @@ -1362,8 +1338,8 @@ msgstr "Nessuna istantanea dello schermo" msgid "Search" msgstr "Cerca" -msgid "Searching for VMs..." -msgstr "Ricerca delle macchine virtuali..." +msgid "Searching for VMs…" +msgstr "Ricerca delle macchine virtuali…" msgid "Found %1" msgstr "Trovato %1" @@ -1398,11 +1374,11 @@ msgstr "Disco rigido (%1)" msgid "MFM/RLL or ESDI CD-ROM drives never existed" msgstr "Le unità CD-ROM MFM/RLL o ESDI non sono mai esistite" -msgid "Custom..." -msgstr "Personalizzata..." +msgid "Custom…" +msgstr "Personalizzata…" -msgid "Custom (large)..." -msgstr "Personalizzata (grande)..." +msgid "Custom (large)…" +msgstr "Personalizzata (grande)…" msgid "Add New Hard Disk" msgstr "Aggiungi un nuovo disco rigido" @@ -1462,7 +1438,7 @@ msgid "Don't overwrite" msgstr "Non sovrascrivere" msgid "Raw image" -msgstr "Immagine RAW" +msgstr "Immagine grezza" msgid "HDI image" msgstr "Immagine HDI" @@ -1521,21 +1497,6 @@ msgstr "Le marche temporali del disco padre e figlio non corrispondono" msgid "Could not fix VHD timestamp." msgstr "Impossibile correggere la marca temporale VHD." -msgid "MFM/RLL" -msgstr "MFM/RLL" - -msgid "XTA" -msgstr "XTA" - -msgid "ESDI" -msgstr "ESDI" - -msgid "IDE" -msgstr "IDE" - -msgid "ATAPI" -msgstr "ATAPI" - msgid "CD-ROM %1 (%2): %3" msgstr "CD-ROM %1 (%2): %3" @@ -1686,14 +1647,14 @@ msgstr "Strumento tablet" msgid "About &Qt" msgstr "Informazioni su &Qt" -msgid "&MCA devices..." -msgstr "Dispositivi MCA..." +msgid "&MCA devices…" +msgstr "Dispositivi MCA…" msgid "Show non-&primary monitors" msgstr "Mostra i monitor non &primari" -msgid "Open screenshots &folder..." -msgstr "Apri la ca&rtella screenshots..." +msgid "Open screenshots &folder…" +msgstr "Apri la ca&rtella screenshots…" msgid "Appl&y fullscreen stretch mode when maximized" msgstr "Applica adattamento sc&hermo intero in modalità massimizzata" @@ -1713,8 +1674,8 @@ msgstr "&Connesso" msgid "Clear image &history" msgstr "Cancella la cr&onologia delle immagini" -msgid "Create..." -msgstr "Crea..." +msgid "Create…" +msgstr "Crea…" msgid "Host CD/DVD Drive (%1)" msgstr "Unità CD/DVD host (%1)" @@ -1755,8 +1716,8 @@ msgstr "Shader" msgid "Remove" msgstr "Rimuovi" -msgid "Browse..." -msgstr "Sfoglia..." +msgid "Browse…" +msgstr "Sfoglia…" msgid "Couldn't create OpenGL context." msgstr "Impossibile creare il contesto OpenGL." @@ -1845,8 +1806,8 @@ msgstr "Porta seriale passante 3" msgid "Serial port passthrough 4" msgstr "Porta seriale passante 4" -msgid "Renderer &options..." -msgstr "&Opzioni renderizzatore..." +msgid "Renderer &options…" +msgstr "&Opzioni renderizzatore…" msgid "PC/XT Keyboard" msgstr "Tastiera PC/XT" @@ -1899,8 +1860,8 @@ msgstr "3M MicroTouch (seriale)" msgid "Default Baud rate" msgstr "Velocità di trasmissione predefinita" -msgid "[COM] Standard Hayes-compliant Modem" -msgstr "[COM] Modem standard conforme a Hayes" +msgid "Standard Hayes-compliant Modem" +msgstr "Modem standard conforme a Hayes" msgid "Roland MT-32 Emulation" msgstr "Emulazione Roland MT-32" @@ -1983,6 +1944,9 @@ msgstr "IRQ porta seriale" msgid "Parallel port IRQ" msgstr "IRQ porta parallela" +msgid "Hard disk" +msgstr "Disco rigido" + msgid "BIOS Revision" msgstr "Revisione BIOS" @@ -2058,9 +2022,6 @@ msgstr "Ingresso passante MIDI" msgid "MIDI Clockout" msgstr "Sincronizzazione MIDI" -msgid "SoundFont" -msgstr "SoundFont" - msgid "Output Gain" msgstr "Guadagno uscita" @@ -2440,10 +2401,10 @@ msgid "Wheel" msgstr "Rotellina" msgid "Five + Wheel" -msgstr "Cinque + Rotellina" +msgstr "Cinque + rotellina" msgid "Five + 2 Wheels" -msgstr "Cinque + 2 Rotelline" +msgstr "Cinque + 2 rotelline" msgid "A3 - SMT2 Serial / SMT3(R)V" msgstr "A3 - SMT2 seriale / SMT3(R)V" @@ -2853,9 +2814,6 @@ msgstr "Attiva/disattiva schermo intero" msgid "Toggle UI in fullscreen" msgstr "Attivare/disattivare interfaccia utente in modalità a schermo intero" -msgid "Screenshot" -msgstr "Istantanea dello schermo" - msgid "Release mouse pointer" msgstr "Rilascia il puntatore del mouse" @@ -2970,8 +2928,8 @@ msgstr "Visita la pagina" msgid "Update check" msgstr "Verifica disponibilità degli aggiornamenti" -msgid "Checking for updates..." -msgstr "Ricerca degli aggiornamenti..." +msgid "Checking for updates…" +msgstr "Ricerca degli aggiornamenti…" msgid "86Box Update" msgstr "Aggiornamento di 86Box" @@ -3009,8 +2967,8 @@ msgstr "Luminosità" msgid "Sharpness" msgstr "Nitidezza" -msgid "&CGA composite settings..." -msgstr "Impostazioni video composito &CGA..." +msgid "&CGA composite settings…" +msgstr "Impostazioni video composito &CGA…" msgid "CGA composite settings" msgstr "Impostazioni video composito CGA" @@ -3018,8 +2976,8 @@ msgstr "Impostazioni video composito CGA" msgid "Monitor EDID" msgstr "EDID del monitor" -msgid "Export..." -msgstr "Esporta..." +msgid "Export…" +msgstr "Esporta…" msgid "Export EDID" msgstr "Esporta EDID" @@ -3044,3 +3002,24 @@ msgstr "Scura" msgid "Search:" msgstr "Cerca:" + +msgid "Force interpretation" +msgstr "Forza interpretazione" + +msgid "Allow recompilation" +msgstr "Permetti ricompilazione" + +msgid "&Force interpretation" +msgstr "&Forza interpretazione" + +msgid "&Allow recompilation" +msgstr "&Permetti ricompilazione" + +msgid "&Fast forward" +msgstr "" + +msgid "Fast forward" +msgstr "" + +msgid "To change the system directory, stop all running machines." +msgstr "" diff --git a/src/qt/languages/ja-JP.po b/src/qt/languages/ja-JP.po index 8d117f34903..2a7809a47f4 100644 --- a/src/qt/languages/ja-JP.po +++ b/src/qt/languages/ja-JP.po @@ -73,8 +73,8 @@ msgstr "OpenGL (3.0 Core)(&G)" msgid "&VNC" msgstr "VNC(&V)" -msgid "Specify &dimensions..." -msgstr "ディメンションを指定(&D)..." +msgid "Specify &dimensions…" +msgstr "ディメンションを指定(&D)…" msgid "Force &4:3 display ratio" msgstr "4:3の縦横比を強制表示(&4)" @@ -199,11 +199,11 @@ msgstr "メディア(&M)" msgid "&Tools" msgstr "ツール(&T)" -msgid "&Settings..." -msgstr "設定(&S)..." +msgid "&Settings…" +msgstr "設定(&S)…" -msgid "Settings..." -msgstr "設定..." +msgid "Settings…" +msgstr "設定…" msgid "&Update status bar icons" msgstr "ステータスバーのアイコンを更新(&U)" @@ -211,17 +211,38 @@ msgstr "ステータスバーのアイコンを更新(&U)" msgid "Take s&creenshot" msgstr "スクリーンショットを撮る(&C)" +msgid "Take screenshot" +msgstr "スクリーンショットを撮る" + +msgid "Take &raw screenshot" +msgstr "生のスクリーンショットを撮る(&R)" + +msgid "Take raw screenshot" +msgstr "生のスクリーンショットを撮る" + +msgid "C&opy screenshot" +msgstr "スクリーンショットをコピーする(&O)" + +msgid "Copy screenshot" +msgstr "スクリーンショットをコピーする" + +msgid "Copy r&aw screenshot" +msgstr "生のスクリーンショットをコピーする(&A)" + +msgid "Copy raw screenshot" +msgstr "生のスクリーンショットをコピーする" + msgid "S&ound" msgstr "サウンド(&O)" -msgid "&Preferences..." -msgstr "環境設定(&P)..." +msgid "&Preferences…" +msgstr "環境設定(&P)…" msgid "Enable &Discord integration" msgstr "Discord連携機能(&D)" -msgid "Sound &gain..." -msgstr "音量調整(&G)..." +msgid "Sound &gain…" +msgstr "音量調整(&G)…" msgid "Begin trace" msgstr "トレース開始" @@ -232,20 +253,20 @@ msgstr "トレース終了" msgid "&Help" msgstr "ヘルプ(&H)" -msgid "&Documentation..." -msgstr "文書(&D)..." +msgid "&Documentation…" +msgstr "文書(&D)…" -msgid "&About 86Box..." -msgstr "86Boxのバージョン情報(&A)..." +msgid "&About 86Box…" +msgstr "86Boxのバージョン情報(&A)…" -msgid "&New image..." -msgstr "新規イメージ(&N)..." +msgid "&New image…" +msgstr "新規イメージ(&N)…" -msgid "&Existing image..." -msgstr "既存のイメージを開く(&E)..." +msgid "&Existing image…" +msgstr "既存のイメージを開く(&E)…" -msgid "Existing image (&Write-protected)..." -msgstr "既存のイメージを開く(書き込み禁止)(&W)..." +msgid "Existing image (&Write-protected)…" +msgstr "既存のイメージを開く(書き込み禁止)(&W)…" msgid "&Record" msgstr "録音(&R)" @@ -262,11 +283,11 @@ msgstr "最後まで早送り(&F)" msgid "E&ject" msgstr "取り出す(&J)" -msgid "&Image..." -msgstr "イメージ(&I)..." +msgid "&Image…" +msgstr "イメージ(&I)…" -msgid "E&xport to 86F..." -msgstr "86Fイメージにエクスポート(&X)..." +msgid "E&xport to 86F…" +msgstr "86Fイメージにエクスポート(&X)…" msgid "&Mute" msgstr "ミュート(&M)" @@ -277,8 +298,8 @@ msgstr "なし(&M)" msgid "Reload previous image" msgstr "前のイメージを再読み込み" -msgid "&Folder..." -msgstr "フォルダ(&F)..." +msgid "&Folder…" +msgstr "フォルダ(&F)…" msgid "Preferences" msgstr "環境設定" @@ -424,17 +445,17 @@ msgstr "ジョイスティック:" msgid "Joystick" msgstr "ジョイスティック" -msgid "Joystick 1..." -msgstr "ジョイスティック1..." +msgid "Joystick 1…" +msgstr "ジョイスティック1…" -msgid "Joystick 2..." -msgstr "ジョイスティック2..." +msgid "Joystick 2…" +msgstr "ジョイスティック2…" -msgid "Joystick 3..." -msgstr "ジョイスティック3..." +msgid "Joystick 3…" +msgstr "ジョイスティック3…" -msgid "Joystick 4..." -msgstr "ジョイスティック4..." +msgid "Joystick 4…" +msgstr "ジョイスティック4…" msgid "Sound card #1:" msgstr "サウンドカード1:" @@ -523,10 +544,10 @@ msgstr "パラレルポート3" msgid "Parallel port 4" msgstr "パラレルポート4" -msgid "FD Controller:" +msgid "Floppy disk controller:" msgstr "FDDコントローラー:" -msgid "CD-ROM Controller:" +msgid "CD-ROM controller:" msgstr "CD-ROMコントローラー:" msgid "Tertiary IDE Controller" @@ -535,11 +556,11 @@ msgstr "第三IDEコントローラー" msgid "Quaternary IDE Controller" msgstr "第四IDEコントローラー" -msgid "Hard disk" -msgstr "ハードディスク" +msgid "Hard disk controllers" +msgstr "ハードディスクコントローラー" -msgid "SCSI" -msgstr "SCSI" +msgid "SCSI controllers" +msgstr "SCSIコントローラー" msgid "Controller 1:" msgstr "コントローラー1:" @@ -562,11 +583,11 @@ msgstr "ハード ディスク:" msgid "Firmware Version" msgstr "ファームウェアバージョン" -msgid "&New..." -msgstr "新規(&N)..." +msgid "&New…" +msgstr "新規(&N)…" -msgid "&Existing..." -msgstr "既定(&E)..." +msgid "&Existing…" +msgstr "既定(&E)…" msgid "&Remove" msgstr "削除(&R)" @@ -874,9 +895,6 @@ msgstr "4ボタン式ゲームパッド" msgid "6-button gamepad" msgstr "6ボタン式ゲームパッド" -msgid "Gravis PC GamePad" -msgstr "Gravis PC GamePad" - msgid "2-button flight yoke" msgstr "2ボタン式操縦桿" @@ -904,51 +922,6 @@ msgstr "ステアリングホイール(3軸、3ボタン)" msgid "Steering wheel (3-axis, 4-button)" msgstr "ステアリングホイール(3軸、4ボタン)" -msgid "CH Flightstick" -msgstr "CH Flightstick" - -msgid "CH Flightstick + CH Pedals" -msgstr "CH Flightstick + CH Pedals" - -msgid "CH Flightstick + CH Pedals Pro" -msgstr "CH Flightstick + CH Pedals Pro" - -msgid "CH Flightstick Pro" -msgstr "CH Flightstick Pro" - -msgid "CH Flightstick Pro + CH Pedals" -msgstr "CH Flightstick Pro + CH Pedals" - -msgid "CH Flightstick Pro + CH Pedals Pro" -msgstr "CH Flightstick Pro + CH Pedals Pro" - -msgid "CH Virtual Pilot" -msgstr "CH Virtual Pilot" - -msgid "CH Virtual Pilot + CH Pedals" -msgstr "CH Virtual Pilot + CH Pedals" - -msgid "CH Virtual Pilot + CH Pedals Pro" -msgstr "CH Virtual Pilot + CH Pedals Pro" - -msgid "CH Virtual Pilot Pro" -msgstr "CH Virtual Pilot Pro" - -msgid "CH Virtual Pilot Pro + CH Pedals" -msgstr "CH Virtual Pilot Pro + CH Pedals" - -msgid "CH Virtual Pilot Pro + CH Pedals Pro" -msgstr "CH Virtual Pilot Pro + CH Pedals Pro" - -msgid "Microsoft SideWinder Pad" -msgstr "Microsoft SideWinderパッド" - -msgid "Thrustmaster Flight Control System" -msgstr "Thrustmaster Flight Control System" - -msgid "Thrustmaster FCS + Rudder Control System" -msgstr "Thrustmaster FCS + Rudder Control System" - msgid "Thrustmaster Formula T1/T2 with adapter" msgstr "アダプター付き Thrustmaster Formula T1/T2" @@ -1003,11 +976,17 @@ msgstr "内蔵デバイス" msgid "&File" msgstr "ファイル(&F)" -msgid "&New machine..." -msgstr "新しいマシン(&N)..." +msgid "&New machine…" +msgstr "新しいマシン(&N)…" + +msgid "New machine…" +msgstr "新しいマシン…" + +msgid "New machine" +msgstr "新しいマシン" -msgid "&Check for updates..." -msgstr "アップデートを確認中(&C)..." +msgid "&Check for updates…" +msgstr "アップデートを確認中(&C)…" msgid "Exit" msgstr "終了" @@ -1106,7 +1085,7 @@ msgid "Ctrl+Alt+Del" msgstr "Ctrl+Alt+Del" msgid "Press Ctrl+Alt+Del" -msgstr "Ctrl+Alt+DELを押す" +msgstr "Ctrl+Alt+Delを押す" msgid "Press Ctrl+Alt+Esc" msgstr "Ctrl+Alt+Escを押す" @@ -1177,8 +1156,8 @@ msgstr "選択した設定ファイルを読み込むことができませんで msgid "Use regular expressions in search box" msgstr "検索ボックスで正規表現を使用する" -msgid "%1 machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" -msgstr "現在、%1台の仮想マシンがアクティブです。それでもVMマネージャーを終了しますか?" +msgid "%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" +msgstr "現在、%n台の仮想マシンがアクティブです。それでもVMマネージャーを終了しますか?" msgid "Add new system wizard" msgstr "新しいシステムを追加するためのウィザード" @@ -1258,26 +1237,23 @@ msgstr "表示名を設定する" msgid "Enter the new display name (blank to reset)" msgstr "新しい表示名を入力してください(空白にするとリセットされます)" -msgid "Change &display name..." -msgstr "表示名を変更(&D)..." +msgid "Change &display name…" +msgstr "表示名を変更(&D)…" -msgid "Context Menu" -msgstr "コンテキストメニュー" +msgid "&Open folder…" +msgstr "フォルダーを開く(&O)…" -msgid "&Open folder..." -msgstr "フォルダーを開く(&O)..." +msgid "Open p&rinter tray…" +msgstr "プリンタートレイを開く(&R)…" -msgid "Open p&rinter tray..." -msgstr "プリンタートレイを開く(&R)..." - -msgid "Set &icon..." -msgstr "アイコンを設定(&I)..." +msgid "Set &icon…" +msgstr "アイコンを設定(&I)…" msgid "Select an icon" msgstr "アイコンを選択してください" -msgid "C&lone..." -msgstr "クローン(&L)..." +msgid "C&lone…" +msgstr "クローン(&L)…" msgid "Virtual machine \"%1\" (%2) will be cloned into:" msgstr "仮想マシン「%1」 (%2)は、以下の場所にクローンされます:" @@ -1363,8 +1339,8 @@ msgstr "スクリーンショットなし" msgid "Search" msgstr "検索" -msgid "Searching for VMs..." -msgstr "仮想マシンを検索中..." +msgid "Searching for VMs…" +msgstr "仮想マシンを検索中…" msgid "Found %1" msgstr "%1が見つかりました" @@ -1391,7 +1367,7 @@ msgid "ACPI shutdown" msgstr "ACPIシャットダウン" msgid "ACP&I shutdown" -msgstr "ACP&Iシャットダウン" +msgstr "ACPIシャットダウン(&I)" msgid "Hard disk (%1)" msgstr "ハードディスク (%1)" @@ -1399,11 +1375,11 @@ msgstr "ハードディスク (%1)" msgid "MFM/RLL or ESDI CD-ROM drives never existed" msgstr "MFM/RLLやESDI CD-ROMドライブが存在しません" -msgid "Custom..." -msgstr "カスタム..." +msgid "Custom…" +msgstr "カスタム…" -msgid "Custom (large)..." -msgstr "カスタム (大容量)..." +msgid "Custom (large)…" +msgstr "カスタム (大容量)…" msgid "Add New Hard Disk" msgstr "新規のディスクを追加" @@ -1463,7 +1439,7 @@ msgid "Don't overwrite" msgstr "上書きしない" msgid "Raw image" -msgstr "Rawイメージ" +msgstr "生のイメージ" msgid "HDI image" msgstr "HDIイメージ" @@ -1522,21 +1498,6 @@ msgstr "親ディスクと子ディスクのタイムス タンプが一致し msgid "Could not fix VHD timestamp." msgstr "VHD のタイムスタンプを修正できません。" -msgid "MFM/RLL" -msgstr "MFM/RLL" - -msgid "XTA" -msgstr "XTA" - -msgid "ESDI" -msgstr "ESDI" - -msgid "IDE" -msgstr "IDE" - -msgid "ATAPI" -msgstr "ATAPI" - msgid "CD-ROM %1 (%2): %3" msgstr "CD-ROM %1 (%2): %3" @@ -1687,14 +1648,14 @@ msgstr "タブレットツール(&T)" msgid "About &Qt" msgstr "&Qtについて" -msgid "&MCA devices..." -msgstr "&MCAデバイス..." +msgid "&MCA devices…" +msgstr "&MCAデバイス…" msgid "Show non-&primary monitors" msgstr "プライマリーモニター以外のモニターを表示する(&P)" -msgid "Open screenshots &folder..." -msgstr "スクリーンショットフォルダを開く(&F)..." +msgid "Open screenshots &folder…" +msgstr "スクリーンショットフォルダを開く(&F)…" msgid "Appl&y fullscreen stretch mode when maximized" msgstr "最大化時にフルスクリーンストレッチモードを適用(&Y)" @@ -1714,8 +1675,8 @@ msgstr "コネクテッド" msgid "Clear image &history" msgstr "クリア画像履歴(&H)" -msgid "Create..." -msgstr "作成..." +msgid "Create…" +msgstr "作成…" msgid "Host CD/DVD Drive (%1)" msgstr "ホスト CD/DVD ドライブ (%1)" @@ -1724,7 +1685,7 @@ msgid "Unknown Bus" msgstr "不明なバス" msgid "Null Driver" -msgstr "ヌル・ドライバー" +msgstr "ヌルドライバー" msgid "NIC:" msgstr "NIC:" @@ -1756,8 +1717,8 @@ msgstr "シェーダー" msgid "Remove" msgstr "削除" -msgid "Browse..." -msgstr "参照..." +msgid "Browse…" +msgstr "参照…" msgid "Couldn't create OpenGL context." msgstr "OpenGLコンテキストを作成できませんでした。" @@ -1835,19 +1796,19 @@ msgid "Novell NetWare 2.x Key Card" msgstr "Novell NetWare 2.xキーカード" msgid "Serial port passthrough 1" -msgstr "シリアル・ポート・パススルー 1" +msgstr "シリアルポートパススルー 1" msgid "Serial port passthrough 2" -msgstr "シリアル・ポート・パススルー 2" +msgstr "シリアルポートパススルー 2" msgid "Serial port passthrough 3" -msgstr "シリアル・ポート・パススルー 3" +msgstr "シリアルポートパススルー 3" msgid "Serial port passthrough 4" -msgstr "シリアル・ポート・パススルー 4" +msgstr "シリアルポートパススルー 4" -msgid "Renderer &options..." -msgstr "レンダラー設定(&O)..." +msgid "Renderer &options…" +msgstr "レンダラー設定(&O)…" msgid "PC/XT Keyboard" msgstr "PC/XT キーボード" @@ -1900,8 +1861,8 @@ msgstr "3Mマイクロタッチ(シリアル)" msgid "Default Baud rate" msgstr "デフォルトのボーレート" -msgid "[COM] Standard Hayes-compliant Modem" -msgstr "[COM] 標準ヘイズ準拠モデム" +msgid "Standard Hayes-compliant Modem" +msgstr "標準ヘイズ準拠モデム" msgid "Roland MT-32 Emulation" msgstr "Roland MT-32エミュレーション" @@ -1984,6 +1945,9 @@ msgstr "シリアルポートのIRQ" msgid "Parallel port IRQ" msgstr "パラレルポートのIRQ" +msgid "Hard disk" +msgstr "ハードディスク" + msgid "BIOS Revision" msgstr "BIOSリビジョン" @@ -2059,9 +2023,6 @@ msgstr "MIDI入力のパススルー" msgid "MIDI Clockout" msgstr "MIDIクロックの出力" -msgid "SoundFont" -msgstr "サウンドフォント" - msgid "Output Gain" msgstr "出力ゲイン" @@ -2072,10 +2033,10 @@ msgid "Chorus Voices" msgstr "コーラスの声" msgid "Chorus Level" -msgstr "コーラス・レベル" +msgstr "コーラスレベル" msgid "Chorus Speed" -msgstr "コーラス・スピード" +msgstr "コーラススピード" msgid "Chorus Depth" msgstr "コーラスの深さ" @@ -2087,16 +2048,16 @@ msgid "Reverb" msgstr "リバーブ" msgid "Reverb Room Size" -msgstr "リバーブ・ルームの大きさ" +msgstr "リバーブルームの大きさ" msgid "Reverb Damping" -msgstr "リバーブ・ダンピング" +msgstr "リバーブダンピング" msgid "Reverb Width" msgstr "リバーブ幅" msgid "Reverb Level" -msgstr "リバーブ・レベル" +msgstr "リバーブレベル" msgid "Interpolation Method" msgstr "補間法" @@ -2111,7 +2072,7 @@ msgid "Reversed stereo" msgstr "逆ステレオ" msgid "Nice ramp" -msgstr "ナイス・スロープ" +msgstr "ナイススロープ" msgid "Hz" msgstr "ヘルツ" @@ -2201,7 +2162,7 @@ msgid "SID Filter Strength" msgstr "SIDフィルターの強度" msgid "Surround module" -msgstr "サラウンド・モジュール" +msgstr "サラウンドモジュール" msgid "SB Address" msgstr "SBアドレス" @@ -2276,7 +2237,7 @@ msgid "Display type" msgstr "表示タイプ" msgid "Composite type" -msgstr "コンポジット・タイプ" +msgstr "コンポジットタイプ" msgid "RGB type" msgstr "RGBタイプ" @@ -2285,7 +2246,7 @@ msgid "Line doubling type" msgstr "ライン倍増タイプ" msgid "Snow emulation" -msgstr "スノー・エミュレーション" +msgstr "スノーエミュレーション" msgid "Monitor type" msgstr "モニタータイプ" @@ -2312,7 +2273,7 @@ msgid "Font" msgstr "フォント" msgid "Bilinear filtering" -msgstr "バイリニア・フィルタリング" +msgstr "バイリニアフィルタリング" msgid "Video chroma-keying" msgstr "ビデオのクロマキー処理" @@ -2606,16 +2567,16 @@ msgid "Apply overscan deltas" msgstr "オーバースキャンデルタを適用する" msgid "Mono Interlaced" -msgstr "モノラル・インターレース" +msgstr "モノラルインターレース" msgid "Mono Non-Interlaced" -msgstr "モノラル・ノンインターレース" +msgstr "モノラルノンインターレース" msgid "Color Interlaced" -msgstr "カラー・インターレース" +msgstr "カラーインターレース" msgid "Color Non-Interlaced" -msgstr "カラー・ノンインターレース" +msgstr "カラーノンインターレース" msgid "3Dfx Voodoo Graphics" msgstr "3dfx Voodooグラフィック" @@ -2651,7 +2612,7 @@ msgid "Stereo LPT DAC" msgstr "ステレオLPT DAC" msgid "Generic Text Printer" -msgstr "汎用テキスト・プリンタ" +msgstr "汎用テキストプリンタ" msgid "Generic ESC/P 2 Dot-Matrix Printer" msgstr "汎用ESC/P 2ドットマトリクスプリンタ" @@ -2663,19 +2624,19 @@ msgid "Generic PCL5e Printer" msgstr "汎用PCL5eプリンタ" msgid "Parallel Line Internet Protocol" -msgstr "パラレルライン・インターネット・プロトコル" +msgstr "パラレルラインインターネットプロトコル" msgid "Protection Dongle for Savage Quest" -msgstr "サベージ・クエスト用プロテクション・ドングル" +msgstr "サベージクエスト用プロテクションドングル" msgid "Serial Passthrough Device" -msgstr "シリアル・ポート・パススルー・デバイス" +msgstr "シリアルポートパススルーデバイス" msgid "Passthrough Mode" msgstr "パススルーモード" msgid "Host Serial Device" -msgstr "ホスト・シリアル・デバイス" +msgstr "ホストシリアルデバイス" msgid "Name of pipe" msgstr "パイプ名" @@ -2854,9 +2815,6 @@ msgstr "フルスクリーン表示を切り替える" msgid "Toggle UI in fullscreen" msgstr "全画面表示時にUIを切り替える" -msgid "Screenshot" -msgstr "スクリーンショット" - msgid "Release mouse pointer" msgstr "マウスポインターを解放する" @@ -2971,8 +2929,8 @@ msgstr "ダウンロードページをご覧ください" msgid "Update check" msgstr "アップデートチェック" -msgid "Checking for updates..." -msgstr "アップデートを確認中..." +msgid "Checking for updates…" +msgstr "アップデートを確認中…" msgid "86Box Update" msgstr "86Box アップデート" @@ -3010,8 +2968,8 @@ msgstr "明るさ" msgid "Sharpness" msgstr "シャープネス" -msgid "&CGA composite settings..." -msgstr "CGA複合モードの設定(&C)..." +msgid "&CGA composite settings…" +msgstr "CGA複合モードの設定(&C)…" msgid "CGA composite settings" msgstr "CGA複合モードの設定" @@ -3019,8 +2977,8 @@ msgstr "CGA複合モードの設定" msgid "Monitor EDID" msgstr "モニターのEDID" -msgid "Export..." -msgstr "エクスポート..." +msgid "Export…" +msgstr "エクスポート…" msgid "Export EDID" msgstr "EDIDのエクスポート" @@ -3045,3 +3003,24 @@ msgstr "暗闇" msgid "Search:" msgstr "検索:" + +msgid "Force interpretation" +msgstr "解釈を強制する" + +msgid "Allow recompilation" +msgstr "再コンパイルを許可する" + +msgid "&Force interpretation" +msgstr "解釈を強制する(&F)" + +msgid "&Allow recompilation" +msgstr "再コンパイルを許可する(&A)" + +msgid "&Fast forward" +msgstr "" + +msgid "Fast forward" +msgstr "" + +msgid "To change the system directory, stop all running machines." +msgstr "" diff --git a/src/qt/languages/ko-KR.po b/src/qt/languages/ko-KR.po index 4994e8e6699..0318e85f322 100644 --- a/src/qt/languages/ko-KR.po +++ b/src/qt/languages/ko-KR.po @@ -66,8 +66,8 @@ msgstr "OpenGL (3.0 Core)(&G)" msgid "&VNC" msgstr "VNC(&V)" -msgid "Specify &dimensions..." -msgstr "창 크기 지정하기(&D)..." +msgid "Specify &dimensions…" +msgstr "창 크기 지정하기(&D)…" msgid "Force &4:3 display ratio" msgstr "화면 비율을 4:3으로 맞추기(&4)" @@ -192,11 +192,11 @@ msgstr "미디어(&M)" msgid "&Tools" msgstr "도구(&T)" -msgid "&Settings..." -msgstr "설정(&S)..." +msgid "&Settings…" +msgstr "설정(&S)…" -msgid "Settings..." -msgstr "설정..." +msgid "Settings…" +msgstr "설정…" msgid "&Update status bar icons" msgstr "상태 바 아이콘 갱신하기(&U)" @@ -204,17 +204,38 @@ msgstr "상태 바 아이콘 갱신하기(&U)" msgid "Take s&creenshot" msgstr "스크린샷 찍기(&C)" +msgid "Take screenshot" +msgstr "스크린샷 찍기" + +msgid "Take &raw screenshot" +msgstr "원본 스크린샷 찍기(&R)" + +msgid "Take raw screenshot" +msgstr "원본 스크린샷 찍기" + +msgid "C&opy screenshot" +msgstr "스크린샷 복사하세요(&O)" + +msgid "Copy screenshot" +msgstr "스크린샷 복사하세요" + +msgid "Copy r&aw screenshot" +msgstr "원본 스크린샷 복사하세요(&A)" + +msgid "Copy raw screenshot" +msgstr "원본 스크린샷 복사하세요" + msgid "S&ound" msgstr "사운드(&O)" -msgid "&Preferences..." -msgstr "환경설정(&P)..." +msgid "&Preferences…" +msgstr "환경설정(&P)…" msgid "Enable &Discord integration" msgstr "디스코드 연동 활성화하기(&D)" -msgid "Sound &gain..." -msgstr "음량 증폭(&G)..." +msgid "Sound &gain…" +msgstr "음량 증폭(&G)…" msgid "Begin trace" msgstr "추적 시작하기" @@ -225,20 +246,20 @@ msgstr "추적 끝내기" msgid "&Help" msgstr "도움말(&H)" -msgid "&Documentation..." -msgstr "문서(&D)..." +msgid "&Documentation…" +msgstr "문서(&D)…" -msgid "&About 86Box..." -msgstr "86Box에 대해(&A)..." +msgid "&About 86Box…" +msgstr "86Box에 대해(&A)…" -msgid "&New image..." -msgstr "새 이미지(&N)..." +msgid "&New image…" +msgstr "새 이미지(&N)…" -msgid "&Existing image..." -msgstr "이미지 불러오기(&E)..." +msgid "&Existing image…" +msgstr "이미지 불러오기(&E)…" -msgid "Existing image (&Write-protected)..." -msgstr "이미지 불러오기 (쓰기방지)(&W)..." +msgid "Existing image (&Write-protected)…" +msgstr "이미지 불러오기 (쓰기방지)(&W)…" msgid "&Record" msgstr "녹음하기(&R)" @@ -255,11 +276,11 @@ msgstr "맨끝으로 빨리감기(&F)" msgid "E&ject" msgstr "꺼내기(&J)" -msgid "&Image..." -msgstr "이미지(&I)..." +msgid "&Image…" +msgstr "이미지(&I)…" -msgid "E&xport to 86F..." -msgstr "86F로 보내기(&X)..." +msgid "E&xport to 86F…" +msgstr "86F로 보내기(&X)…" msgid "&Mute" msgstr "음소거(&M)" @@ -270,8 +291,8 @@ msgstr "비었음(&M)" msgid "Reload previous image" msgstr "이전 이미지 다시 불러오기" -msgid "&Folder..." -msgstr "폴더(&F)..." +msgid "&Folder…" +msgstr "폴더(&F)…" msgid "Preferences" msgstr "환경설정" @@ -417,17 +438,17 @@ msgstr "조이스틱:" msgid "Joystick" msgstr "조이스틱" -msgid "Joystick 1..." -msgstr "조이스틱 1..." +msgid "Joystick 1…" +msgstr "조이스틱 1…" -msgid "Joystick 2..." -msgstr "조이스틱 2..." +msgid "Joystick 2…" +msgstr "조이스틱 2…" -msgid "Joystick 3..." -msgstr "조이스틱 3..." +msgid "Joystick 3…" +msgstr "조이스틱 3…" -msgid "Joystick 4..." -msgstr "조이스틱 4..." +msgid "Joystick 4…" +msgstr "조이스틱 4…" msgid "Sound card #1:" msgstr "사운드 카드 1:" @@ -516,10 +537,10 @@ msgstr "병렬 포트 3" msgid "Parallel port 4" msgstr "병렬 포트 4" -msgid "FD Controller:" -msgstr "FD 컨트롤러:" +msgid "Floppy disk controller:" +msgstr "플로피 디스크 컨트롤러:" -msgid "CD-ROM Controller:" +msgid "CD-ROM controller:" msgstr "CD-ROM 컨트롤러:" msgid "Tertiary IDE Controller" @@ -528,11 +549,11 @@ msgstr "제3의 IDE 컨트롤러" msgid "Quaternary IDE Controller" msgstr "제4의 IDE 컨트롤러" -msgid "Hard disk" -msgstr "하드 디스크" +msgid "Hard disk controllers" +msgstr "하드 디스크 컨트롤러" -msgid "SCSI" -msgstr "SCSI" +msgid "SCSI controllers" +msgstr "SCSI 컨트롤러" msgid "Controller 1:" msgstr "컨트롤러 1:" @@ -555,11 +576,11 @@ msgstr "하드 디스크:" msgid "Firmware Version" msgstr "펌웨어 버전" -msgid "&New..." -msgstr "새로 만들기(&N)..." +msgid "&New…" +msgstr "새로 만들기(&N)…" -msgid "&Existing..." -msgstr "불러오기(&E)..." +msgid "&Existing…" +msgstr "불러오기(&E)…" msgid "&Remove" msgstr "목록에서 제거(&R)" @@ -867,9 +888,6 @@ msgstr "4버튼 게임패드" msgid "6-button gamepad" msgstr "6버튼 게임패드" -msgid "Gravis PC GamePad" -msgstr "Gravis PC GamePad" - msgid "2-button flight yoke" msgstr "2버튼 비행 조종간" @@ -897,51 +915,6 @@ msgstr "조타륜 (3축, 3버튼)" msgid "Steering wheel (3-axis, 4-button)" msgstr "조타륜 (3축, 4버튼)" -msgid "CH Flightstick" -msgstr "CH Flightstick" - -msgid "CH Flightstick + CH Pedals" -msgstr "CH Flightstick + CH Pedals" - -msgid "CH Flightstick + CH Pedals Pro" -msgstr "CH Flightstick + CH Pedals Pro" - -msgid "CH Flightstick Pro" -msgstr "CH Flightstick Pro" - -msgid "CH Flightstick Pro + CH Pedals" -msgstr "CH Flightstick Pro + CH Pedals" - -msgid "CH Flightstick Pro + CH Pedals Pro" -msgstr "CH Flightstick Pro + CH Pedals Pro" - -msgid "CH Virtual Pilot" -msgstr "CH Virtual Pilot" - -msgid "CH Virtual Pilot + CH Pedals" -msgstr "CH Virtual Pilot + CH Pedals" - -msgid "CH Virtual Pilot + CH Pedals Pro" -msgstr "CH Virtual Pilot + CH Pedals Pro" - -msgid "CH Virtual Pilot Pro" -msgstr "CH Virtual Pilot Pro" - -msgid "CH Virtual Pilot Pro + CH Pedals" -msgstr "CH Virtual Pilot Pro + CH Pedals" - -msgid "CH Virtual Pilot Pro + CH Pedals Pro" -msgstr "CH Virtual Pilot Pro + CH Pedals Pro" - -msgid "Microsoft SideWinder Pad" -msgstr "Microsoft SideWinder Pad" - -msgid "Thrustmaster Flight Control System" -msgstr "Thrustmaster Flight Control System" - -msgid "Thrustmaster FCS + Rudder Control System" -msgstr "Thrustmaster FCS + Rudder Control System" - msgid "Thrustmaster Formula T1/T2 with adapter" msgstr "어댑터 포함 Thrustmaster Formula T1/T2" @@ -996,11 +969,17 @@ msgstr "내부 장치" msgid "&File" msgstr "파일(&F)" -msgid "&New machine..." -msgstr "새로운 기계(&N)..." +msgid "&New machine…" +msgstr "새로운 기계(&N)…" + +msgid "New machine…" +msgstr "새로운 기계…" + +msgid "New machine" +msgstr "새로운 기계" -msgid "&Check for updates..." -msgstr "업데이트 확인 중(&C)..." +msgid "&Check for updates…" +msgstr "업데이트 확인 중(&C)…" msgid "Exit" msgstr "끝내기" @@ -1170,8 +1149,8 @@ msgstr "선택한 구성 파일을 읽기 위해 열 수 없습니다: %1" msgid "Use regular expressions in search box" msgstr "검색 상자에 정규 표현식 사용" -msgid "%1 machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" -msgstr "현재 %1대의 머신이 활성화되어 있습니다. 가상 머신 관리자를 종료하시겠습니까?" +msgid "%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" +msgstr "현재 %n대의 머신이 활성화되어 있습니다. 가상 머신 관리자를 종료하시겠습니까?" msgid "Add new system wizard" msgstr "새로운 시스템을 추가하는 마법사" @@ -1251,26 +1230,23 @@ msgstr "표시 이름 설정" msgid "Enter the new display name (blank to reset)" msgstr "새 표시 이름을 입력하세요 (비워두면 초기화됩니다)" -msgid "Change &display name..." -msgstr "표시 이름 변경(&D)..." +msgid "Change &display name…" +msgstr "표시 이름 변경(&D)…" -msgid "Context Menu" -msgstr "컨텍스트 메뉴" +msgid "&Open folder…" +msgstr "폴더 열기(&O)…" -msgid "&Open folder..." -msgstr "폴더 열기(&O)..." +msgid "Open p&rinter tray…" +msgstr "프린터 트레이를 열기(&R)…" -msgid "Open p&rinter tray..." -msgstr "프린터 트레이를 열기(&R)..." - -msgid "Set &icon..." -msgstr "아이콘 설정(&I)..." +msgid "Set &icon…" +msgstr "아이콘 설정(&I)…" msgid "Select an icon" msgstr "아이콘을 선택하세요" -msgid "C&lone..." -msgstr "클론(&L)..." +msgid "C&lone…" +msgstr "클론(&L)…" msgid "Virtual machine \"%1\" (%2) will be cloned into:" msgstr "가상 머신 \"%1\" (%2)는 다음으로 복제됩니다:" @@ -1356,8 +1332,8 @@ msgstr "스크린샷 없음" msgid "Search" msgstr "검색" -msgid "Searching for VMs..." -msgstr "가상 머신을 검색 중입니다..." +msgid "Searching for VMs…" +msgstr "가상 머신을 검색 중입니다…" msgid "Found %1" msgstr "%1 발견됨" @@ -1384,7 +1360,7 @@ msgid "ACPI shutdown" msgstr "ACPI 종료" msgid "ACP&I shutdown" -msgstr "ACP&I 종료" +msgstr "ACPI 종료(&I)" msgid "Hard disk (%1)" msgstr "하드 디스크 (%1)" @@ -1392,11 +1368,11 @@ msgstr "하드 디스크 (%1)" msgid "MFM/RLL or ESDI CD-ROM drives never existed" msgstr "MFM/RLL 또는 ESDI CD-ROM 드라이브가 존재하지 않습니다" -msgid "Custom..." -msgstr "사용자 설정..." +msgid "Custom…" +msgstr "사용자 설정…" -msgid "Custom (large)..." -msgstr "사용자 설정 (대용량)..." +msgid "Custom (large)…" +msgstr "사용자 설정 (대용량)…" msgid "Add New Hard Disk" msgstr "새로 생성" @@ -1456,7 +1432,7 @@ msgid "Don't overwrite" msgstr "덮어쓰지 않음" msgid "Raw image" -msgstr "Raw 이미지" +msgstr "원본 이미지" msgid "HDI image" msgstr "HDI 이미지" @@ -1515,21 +1491,6 @@ msgstr "부모 디스크와 자식 디스크의 타임스탬프가 일치하지 msgid "Could not fix VHD timestamp." msgstr "VHD 타임스탬프를 고칠 수 없습니다." -msgid "MFM/RLL" -msgstr "MFM/RLL" - -msgid "XTA" -msgstr "XTA" - -msgid "ESDI" -msgstr "ESDI" - -msgid "IDE" -msgstr "IDE" - -msgid "ATAPI" -msgstr "ATAPI" - msgid "CD-ROM %1 (%2): %3" msgstr "CD-ROM %1 (%2): %3" @@ -1680,14 +1641,14 @@ msgstr "태블릿 도구(&T)" msgid "About &Qt" msgstr "&Qt 소개" -msgid "&MCA devices..." -msgstr "&MCA 장치..." +msgid "&MCA devices…" +msgstr "&MCA 장치…" msgid "Show non-&primary monitors" msgstr "기본 모니터가 아닌 모니터 표시(&P)" -msgid "Open screenshots &folder..." -msgstr "스크린샷 폴더 열기(&F)..." +msgid "Open screenshots &folder…" +msgstr "스크린샷 폴더 열기(&F)…" msgid "Appl&y fullscreen stretch mode when maximized" msgstr "최대화 시 전체 화면 비율 적용(&Y)" @@ -1707,8 +1668,8 @@ msgstr "&커넥티드" msgid "Clear image &history" msgstr "이미지 기록 지우기(&H)" -msgid "Create..." -msgstr "만들기..." +msgid "Create…" +msgstr "만들기…" msgid "Host CD/DVD Drive (%1)" msgstr "호스트 CD/DVD 드라이브 (%1)" @@ -1749,8 +1710,8 @@ msgstr "셰이더" msgid "Remove" msgstr "제거" -msgid "Browse..." -msgstr "찾아보기..." +msgid "Browse…" +msgstr "찾아보기…" msgid "Couldn't create OpenGL context." msgstr "OpenGL 컨텍스트를 만들 수 없습니다." @@ -1839,8 +1800,8 @@ msgstr "직렬 포트 패스스루 3" msgid "Serial port passthrough 4" msgstr "직렬 포트 패스스루 4" -msgid "Renderer &options..." -msgstr "렌더러 옵션(&O)..." +msgid "Renderer &options…" +msgstr "렌더러 옵션(&O)…" msgid "PC/XT Keyboard" msgstr "PC/XT 키보드" @@ -1893,8 +1854,8 @@ msgstr "3M 마이크로터치(직렬)" msgid "Default Baud rate" msgstr "기본 보드 속도" -msgid "[COM] Standard Hayes-compliant Modem" -msgstr "[COM] 표준 헤이즈 호환 모뎀" +msgid "Standard Hayes-compliant Modem" +msgstr "표준 헤이즈 호환 모뎀" msgid "Roland MT-32 Emulation" msgstr "롤랜드 MT-32 에뮬레이션" @@ -1977,6 +1938,9 @@ msgstr "시리얼 포트 IRQ" msgid "Parallel port IRQ" msgstr "병렬 포트 IRQ" +msgid "Hard disk" +msgstr "하드 디스크" + msgid "BIOS Revision" msgstr "BIOS 개정" @@ -2052,9 +2016,6 @@ msgstr "미디 입력 패스스루" msgid "MIDI Clockout" msgstr "미디 클럭 출력" -msgid "SoundFont" -msgstr "사운드 글꼴" - msgid "Output Gain" msgstr "출력 게인" @@ -2847,9 +2808,6 @@ msgstr "전체 화면 모드 전환" msgid "Toggle UI in fullscreen" msgstr "" -msgid "Screenshot" -msgstr "스크린샷" - msgid "Release mouse pointer" msgstr "마우스 포인터를 해제합니다" @@ -2964,8 +2922,8 @@ msgstr "다운로드 페이지 방문" msgid "Update check" msgstr "업데이트 확인" -msgid "Checking for updates..." -msgstr "업데이트 확인 중..." +msgid "Checking for updates…" +msgstr "업데이트 확인 중…" msgid "86Box Update" msgstr "86Box 업데이트" @@ -3003,8 +2961,8 @@ msgstr "밝기" msgid "Sharpness" msgstr "선명도" -msgid "&CGA composite settings..." -msgstr "CGA 복합 모드의 설정(&C)..." +msgid "&CGA composite settings…" +msgstr "CGA 복합 모드의 설정(&C)…" msgid "CGA composite settings" msgstr "CGA 복합 모드의 설정" @@ -3012,8 +2970,8 @@ msgstr "CGA 복합 모드의 설정" msgid "Monitor EDID" msgstr "모니터의 EDID" -msgid "Export..." -msgstr "수출..." +msgid "Export…" +msgstr "수출…" msgid "Export EDID" msgstr "EDID 내보내기" @@ -3038,3 +2996,24 @@ msgstr "어둠" msgid "Search:" msgstr "검색:" + +msgid "Force interpretation" +msgstr "강제 해석" + +msgid "Allow recompilation" +msgstr "재컴파일 허용" + +msgid "&Force interpretation" +msgstr "강제 해석(&F)" + +msgid "&Allow recompilation" +msgstr "재컴파일 허용(&A)" + +msgid "&Fast forward" +msgstr "" + +msgid "Fast forward" +msgstr "" + +msgid "To change the system directory, stop all running machines." +msgstr "" diff --git a/src/qt/languages/nb-NO.po b/src/qt/languages/nb-NO.po index 395a56dc9c8..e31768305d8 100644 --- a/src/qt/languages/nb-NO.po +++ b/src/qt/languages/nb-NO.po @@ -66,8 +66,8 @@ msgstr "Open&GL (3.0 Core)" msgid "&VNC" msgstr "&VNC" -msgid "Specify &dimensions..." -msgstr "Angi &dimensjoner..." +msgid "Specify &dimensions…" +msgstr "Angi &dimensjoner…" msgid "Force &4:3 display ratio" msgstr "Tving &4:3-bildeforhold" @@ -192,11 +192,11 @@ msgstr "&Medie" msgid "&Tools" msgstr "&Verktøy" -msgid "&Settings..." -msgstr "&Innstillinger..." +msgid "&Settings…" +msgstr "&Innstillinger…" -msgid "Settings..." -msgstr "Innstillinger..." +msgid "Settings…" +msgstr "Innstillinger…" msgid "&Update status bar icons" msgstr "&Oppdater statuslinjeikoner" @@ -204,17 +204,38 @@ msgstr "&Oppdater statuslinjeikoner" msgid "Take s&creenshot" msgstr "Ta s&kjermbilde" +msgid "Take screenshot" +msgstr "Ta skjermbilde" + +msgid "Take &raw screenshot" +msgstr "Ta &rå skjermbilde" + +msgid "Take raw screenshot" +msgstr "Ta rå skjermbilde" + +msgid "C&opy screenshot" +msgstr "K&opiera skjermbilde" + +msgid "Copy screenshot" +msgstr "Kopiera skjermbilde" + +msgid "Copy r&aw screenshot" +msgstr "Kopiera r&å skjermbilde" + +msgid "Copy raw screenshot" +msgstr "Kopiera rå skjermbilde" + msgid "S&ound" msgstr "L&yd" -msgid "&Preferences..." -msgstr "&Valg..." +msgid "&Preferences…" +msgstr "&Valg…" msgid "Enable &Discord integration" msgstr "Aktiver &Discord-integrasjon" -msgid "Sound &gain..." -msgstr "Lyd&forsterkning..." +msgid "Sound &gain…" +msgstr "Lyd&forsterkning…" msgid "Begin trace" msgstr "Start sporing" @@ -225,20 +246,20 @@ msgstr "Stopp sporing" msgid "&Help" msgstr "&Hjelp" -msgid "&Documentation..." -msgstr "&Dokumentasjon..." +msgid "&Documentation…" +msgstr "&Dokumentasjon…" -msgid "&About 86Box..." -msgstr "&Om 86Box..." +msgid "&About 86Box…" +msgstr "&Om 86Box…" -msgid "&New image..." -msgstr "&Ny diskfil..." +msgid "&New image…" +msgstr "&Ny diskfil…" -msgid "&Existing image..." -msgstr "&Eksisterende diskfil..." +msgid "&Existing image…" +msgstr "&Eksisterende diskfil…" -msgid "Existing image (&Write-protected)..." -msgstr "Eksisterende diskfil (&skrivbeskyttet)..." +msgid "Existing image (&Write-protected)…" +msgstr "Eksisterende diskfil (&skrivbeskyttet)…" msgid "&Record" msgstr "&Spill inn" @@ -255,11 +276,11 @@ msgstr "&Spol frem til slutten" msgid "E&ject" msgstr "M&at ut" -msgid "&Image..." -msgstr "&Diskfil..." +msgid "&Image…" +msgstr "&Diskfil…" -msgid "E&xport to 86F..." -msgstr "E&ksporter til 86F..." +msgid "E&xport to 86F…" +msgstr "E&ksporter til 86F…" msgid "&Mute" msgstr "&Demp" @@ -270,8 +291,8 @@ msgstr "T&øm" msgid "Reload previous image" msgstr "Last inn forrige diskfil" -msgid "&Folder..." -msgstr "&Mappe..." +msgid "&Folder…" +msgstr "&Mappe…" msgid "Preferences" msgstr "Valg" @@ -417,17 +438,17 @@ msgstr "Styrespak:" msgid "Joystick" msgstr "Styrespak" -msgid "Joystick 1..." -msgstr "Styrespak 1..." +msgid "Joystick 1…" +msgstr "Styrespak 1…" -msgid "Joystick 2..." -msgstr "Styrespak 2..." +msgid "Joystick 2…" +msgstr "Styrespak 2…" -msgid "Joystick 3..." -msgstr "Styrespak 3..." +msgid "Joystick 3…" +msgstr "Styrespak 3…" -msgid "Joystick 4..." -msgstr "Styrespak 4..." +msgid "Joystick 4…" +msgstr "Styrespak 4…" msgid "Sound card #1:" msgstr "Lydkort #1:" @@ -516,10 +537,10 @@ msgstr "Parallellport 3" msgid "Parallel port 4" msgstr "Parallellport 4" -msgid "FD Controller:" -msgstr "FD-kontroller:" +msgid "Floppy disk controller:" +msgstr "Diskettkontroller:" -msgid "CD-ROM Controller:" +msgid "CD-ROM controller:" msgstr "CD-ROM-kontroller:" msgid "Tertiary IDE Controller" @@ -528,11 +549,11 @@ msgstr "Tertiær IDE-kontroller" msgid "Quaternary IDE Controller" msgstr "Kvartær IDE-kontroller" -msgid "Hard disk" -msgstr "Harddisk" +msgid "Hard disk controllers" +msgstr "Harddiskkontrollere" -msgid "SCSI" -msgstr "SCSI" +msgid "SCSI controllers" +msgstr "SCSI-kontrollere" msgid "Controller 1:" msgstr "Kontroller 1:" @@ -555,11 +576,11 @@ msgstr "Harddisker:" msgid "Firmware Version" msgstr "Firmware-versjon" -msgid "&New..." -msgstr "&Ny..." +msgid "&New…" +msgstr "&Ny…" -msgid "&Existing..." -msgstr "&Eksisterende..." +msgid "&Existing…" +msgstr "&Eksisterende…" msgid "&Remove" msgstr "&Fjern" @@ -867,9 +888,6 @@ msgstr "4-knapps gamepad" msgid "6-button gamepad" msgstr "6-knapps gamepad" -msgid "Gravis PC GamePad" -msgstr "Gravis PC GamePad" - msgid "2-button flight yoke" msgstr "2-knapps flystyre" @@ -897,51 +915,6 @@ msgstr "Ratt (3-akset, 3-knapps)" msgid "Steering wheel (3-axis, 4-button)" msgstr "Ratt (3-akset, 4-knapps)" -msgid "CH Flightstick" -msgstr "CH Flightstick" - -msgid "CH Flightstick + CH Pedals" -msgstr "CH Flightstick + CH Pedaler" - -msgid "CH Flightstick + CH Pedals Pro" -msgstr "CH Flightstick + CH Pedaler Pro" - -msgid "CH Flightstick Pro" -msgstr "CH Flightstick Pro" - -msgid "CH Flightstick Pro + CH Pedals" -msgstr "CH Flightstick Pro + CH Pedaler" - -msgid "CH Flightstick Pro + CH Pedals Pro" -msgstr "CH Flightstick Pro + CH Pedaler Pro" - -msgid "CH Virtual Pilot" -msgstr "CH Virtual Pilot" - -msgid "CH Virtual Pilot + CH Pedals" -msgstr "CH Virtual Pilot + CH Pedaler" - -msgid "CH Virtual Pilot + CH Pedals Pro" -msgstr "CH Virtual Pilot + CH Pedaler Pro" - -msgid "CH Virtual Pilot Pro" -msgstr "CH Virtual Pilot Pro" - -msgid "CH Virtual Pilot Pro + CH Pedals" -msgstr "CH Virtual Pilot Pro + CH Pedaler" - -msgid "CH Virtual Pilot Pro + CH Pedals Pro" -msgstr "CH Virtual Pilot Pro + CH Pedaler Pro" - -msgid "Microsoft SideWinder Pad" -msgstr "Microsoft SideWinder Pad" - -msgid "Thrustmaster Flight Control System" -msgstr "Thrustmaster Flight Control System" - -msgid "Thrustmaster FCS + Rudder Control System" -msgstr "Thrustmaster FCS + Ror-kontrollsystem" - msgid "Thrustmaster Formula T1/T2 with adapter" msgstr "Thrustmaster Formula T1/T2 med adapter" @@ -996,11 +969,17 @@ msgstr "Intern enhet" msgid "&File" msgstr "&Fil" -msgid "&New machine..." -msgstr "&Ny maskin..." +msgid "&New machine…" +msgstr "&Ny maskin…" + +msgid "New machine…" +msgstr "Ny maskin…" + +msgid "New machine" +msgstr "Ny maskin" -msgid "&Check for updates..." -msgstr "&Sjekk etter oppdateringer..." +msgid "&Check for updates…" +msgstr "&Sjekk etter oppdateringer…" msgid "Exit" msgstr "Avslutt" @@ -1170,8 +1149,8 @@ msgstr "Kan ikke åpne valgt konfigurasjonsfil for lesing: %1" msgid "Use regular expressions in search box" msgstr "Bruk regulære uttrykk i søkeboksen" -msgid "%1 machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" -msgstr "%1 maskin(er) er for øyeblikket aktive. Er du sikker på at du vil avslutte VM-administratoren uansett?" +msgid "%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" +msgstr "%n maskin(er) er for øyeblikket aktive. Er du sikker på at du vil avslutte VM-administratoren uansett?" msgid "Add new system wizard" msgstr "Legg til ny system-veiviser" @@ -1251,26 +1230,23 @@ msgstr "Angi visningsnavn" msgid "Enter the new display name (blank to reset)" msgstr "Skriv inn nytt visningsnavn (tomt for å tilbakestille)" -msgid "Change &display name..." -msgstr "Endre &visningsnavn..." +msgid "Change &display name…" +msgstr "Endre &visningsnavn…" -msgid "Context Menu" -msgstr "Kontekstmeny" +msgid "&Open folder…" +msgstr "&Åpne mappe…" -msgid "&Open folder..." -msgstr "&Åpne mappe..." +msgid "Open p&rinter tray…" +msgstr "Åpne p&rinter-skuff…" -msgid "Open p&rinter tray..." -msgstr "Åpne p&rinter-skuff..." - -msgid "Set &icon..." -msgstr "Angi &ikon..." +msgid "Set &icon…" +msgstr "Angi &ikon…" msgid "Select an icon" msgstr "Velg et ikon" -msgid "C&lone..." -msgstr "K&lon..." +msgid "C&lone…" +msgstr "K&lon…" msgid "Virtual machine \"%1\" (%2) will be cloned into:" msgstr "Virtuell maskin \"%1\" (%2) vil bli klonet til:" @@ -1356,8 +1332,8 @@ msgstr "Ingen skjermbilde" msgid "Search" msgstr "Søk" -msgid "Searching for VMs..." -msgstr "Søker etter VMer..." +msgid "Searching for VMs…" +msgstr "Søker etter VMer…" msgid "Found %1" msgstr "Fant %1" @@ -1392,11 +1368,11 @@ msgstr "Harddisk (%1)" msgid "MFM/RLL or ESDI CD-ROM drives never existed" msgstr "MFM/RLL eller ESDI CD-ROM-stasjoner eksisterte aldri" -msgid "Custom..." -msgstr "Tilpasset..." +msgid "Custom…" +msgstr "Tilpasset…" -msgid "Custom (large)..." -msgstr "Tilpasset (stor)..." +msgid "Custom (large)…" +msgstr "Tilpasset (stor)…" msgid "Add New Hard Disk" msgstr "Legg til ny harddisk" @@ -1515,21 +1491,6 @@ msgstr "Tidsstemplene til overordnet og underordnet disk samsvarer ikke" msgid "Could not fix VHD timestamp." msgstr "Kunne ikke rette VHD-tidsstempel." -msgid "MFM/RLL" -msgstr "MFM/RLL" - -msgid "XTA" -msgstr "XTA" - -msgid "ESDI" -msgstr "ESDI" - -msgid "IDE" -msgstr "IDE" - -msgid "ATAPI" -msgstr "ATAPI" - msgid "CD-ROM %1 (%2): %3" msgstr "CD-ROM %1 (%2): %3" @@ -1680,14 +1641,14 @@ msgstr "&Tegnebrettverktøy" msgid "About &Qt" msgstr "Om &Qt" -msgid "&MCA devices..." -msgstr "&MCA-enheter..." +msgid "&MCA devices…" +msgstr "&MCA-enheter…" msgid "Show non-&primary monitors" msgstr "Vis ikke-&primære skjermer" -msgid "Open screenshots &folder..." -msgstr "Åpne skjermbilde&mappe..." +msgid "Open screenshots &folder…" +msgstr "Åpne skjermbilde&mappe…" msgid "Appl&y fullscreen stretch mode when maximized" msgstr "Bruk fullskjerms&strekkmodus ved maksimering" @@ -1707,8 +1668,8 @@ msgstr "&Koblet til" msgid "Clear image &history" msgstr "Tøm bilde&historikk" -msgid "Create..." -msgstr "Opprett..." +msgid "Create…" +msgstr "Opprett…" msgid "Host CD/DVD Drive (%1)" msgstr "Vert CD/DVD-stasjon (%1)" @@ -1749,8 +1710,8 @@ msgstr "Shader-programmer" msgid "Remove" msgstr "Fjern" -msgid "Browse..." -msgstr "Bla gjennom..." +msgid "Browse…" +msgstr "Bla gjennom…" msgid "Couldn't create OpenGL context." msgstr "Kunne ikke opprette OpenGL-kontekst." @@ -1839,8 +1800,8 @@ msgstr "Seriell port-gjennomkobling 3" msgid "Serial port passthrough 4" msgstr "Seriell port-gjennomkobling 4" -msgid "Renderer &options..." -msgstr "Gjengivelses&alternativer..." +msgid "Renderer &options…" +msgstr "Gjengivelses&alternativer…" msgid "PC/XT Keyboard" msgstr "PC/XT-tastatur" @@ -1893,8 +1854,8 @@ msgstr "3M MicroTouch (seriell)" msgid "Default Baud rate" msgstr "Standard baudrate" -msgid "[COM] Standard Hayes-compliant Modem" -msgstr "[COM] Standard Hayes-kompatibelt modem" +msgid "Standard Hayes-compliant Modem" +msgstr "Standard Hayes-kompatibelt modem" msgid "Roland MT-32 Emulation" msgstr "Roland MT-32-emulering" @@ -1977,6 +1938,9 @@ msgstr "Serieport-IRQ" msgid "Parallel port IRQ" msgstr "Parallellport-IRQ" +msgid "Hard disk" +msgstr "Harddisk" + msgid "BIOS Revision" msgstr "BIOS-revisjon" @@ -2052,9 +2016,6 @@ msgstr "MIDI gjennom" msgid "MIDI Clockout" msgstr "MIDI-klokkeutgang" -msgid "SoundFont" -msgstr "SoundFont" - msgid "Output Gain" msgstr "Utgangsforsterkning" @@ -2847,9 +2808,6 @@ msgstr "Veksle fullskjerm" msgid "Toggle UI in fullscreen" msgstr "" -msgid "Screenshot" -msgstr "Skjermbilde" - msgid "Release mouse pointer" msgstr "Frigi musepeker" @@ -2964,8 +2922,8 @@ msgstr "Besøk nedlastingssiden" msgid "Update check" msgstr "Oppdateringssjekk" -msgid "Checking for updates..." -msgstr "Ser etter oppdateringer..." +msgid "Checking for updates…" +msgstr "Ser etter oppdateringer…" msgid "86Box Update" msgstr "86Box-oppdatering" @@ -3003,8 +2961,8 @@ msgstr "Lysstyrke" msgid "Sharpness" msgstr "Skarphet" -msgid "&CGA composite settings..." -msgstr "&CGA-komposittinnstillinger..." +msgid "&CGA composite settings…" +msgstr "&CGA-komposittinnstillinger…" msgid "CGA composite settings" msgstr "CGA-komposittinnstillinger" @@ -3012,8 +2970,8 @@ msgstr "CGA-komposittinnstillinger" msgid "Monitor EDID" msgstr "EDID for skjerm" -msgid "Export..." -msgstr "Eksporter..." +msgid "Export…" +msgstr "Eksporter…" msgid "Export EDID" msgstr "Eksporter EDID" @@ -3038,3 +2996,24 @@ msgstr "Mørk" msgid "Search:" msgstr "Søk:" + +msgid "Force interpretation" +msgstr "Tving tolkning" + +msgid "Allow recompilation" +msgstr "Tillat rekompilering" + +msgid "&Force interpretation" +msgstr "&Tving tolkning" + +msgid "&Allow recompilation" +msgstr "&Tillat rekompilering" + +msgid "&Fast forward" +msgstr "" + +msgid "Fast forward" +msgstr "" + +msgid "To change the system directory, stop all running machines." +msgstr "" diff --git a/src/qt/languages/nl-NL.po b/src/qt/languages/nl-NL.po index b62014ee72b..3d056a2ea20 100644 --- a/src/qt/languages/nl-NL.po +++ b/src/qt/languages/nl-NL.po @@ -66,8 +66,8 @@ msgstr "Open&GL (3.0 Core)" msgid "&VNC" msgstr "&VNC" -msgid "Specify &dimensions..." -msgstr "Afmetingen opgeven..." +msgid "Specify &dimensions…" +msgstr "Afmetingen opgeven…" msgid "Force &4:3 display ratio" msgstr "Forceer &4:3 beeldverhouding" @@ -192,29 +192,50 @@ msgstr "&Media" msgid "&Tools" msgstr "&Tools" -msgid "&Settings..." -msgstr "&Instellingen..." +msgid "&Settings…" +msgstr "&Instellingen…" -msgid "Settings..." -msgstr "Instellingen..." +msgid "Settings…" +msgstr "Instellingen…" msgid "&Update status bar icons" msgstr "&Statusbalkpictogrammen bijwerken" msgid "Take s&creenshot" +msgstr "Maak een s&chermafbeelding" + +msgid "Take screenshot" msgstr "Maak een schermafbeelding" +msgid "Take &raw screenshot" +msgstr "Maak een &ruw schermafbeelding" + +msgid "Take raw screenshot" +msgstr "Maak een ruw schermafbeelding" + +msgid "C&opy screenshot" +msgstr "K&opieer een schermafbeelding" + +msgid "Copy screenshot" +msgstr "Kopieer een schermafbeelding" + +msgid "Copy r&aw screenshot" +msgstr "Kopieer een r&uw schermafbeelding" + +msgid "Copy raw screenshot" +msgstr "Kopieer een ruw schermafbeelding" + msgid "S&ound" msgstr "&Geluid" -msgid "&Preferences..." -msgstr "&Voorkeuren..." +msgid "&Preferences…" +msgstr "&Voorkeuren…" msgid "Enable &Discord integration" msgstr "&Discord integratie inschakelen" -msgid "Sound &gain..." -msgstr "&Geluidsversterking..." +msgid "Sound &gain…" +msgstr "&Geluidsversterking…" msgid "Begin trace" msgstr "Begin traceren" @@ -225,20 +246,20 @@ msgstr "Beëindig traceren" msgid "&Help" msgstr "&Help" -msgid "&Documentation..." -msgstr "&Documentatie..." +msgid "&Documentation…" +msgstr "&Documentatie…" -msgid "&About 86Box..." -msgstr "&Over 86Box..." +msgid "&About 86Box…" +msgstr "&Over 86Box…" -msgid "&New image..." -msgstr "&Nieuw imagebestand..." +msgid "&New image…" +msgstr "&Nieuw imagebestand…" -msgid "&Existing image..." -msgstr "&Bestaand imagebestand..." +msgid "&Existing image…" +msgstr "&Bestaand imagebestand…" -msgid "Existing image (&Write-protected)..." -msgstr "Bestaand imagebestand (&Schrijfbeveiligd)..." +msgid "Existing image (&Write-protected)…" +msgstr "Bestaand imagebestand (&Schrijfbeveiligd)…" msgid "&Record" msgstr "&Opnemen" @@ -255,11 +276,11 @@ msgstr "&Snel vooruit naar het einde" msgid "E&ject" msgstr "&Uitwerpen" -msgid "&Image..." -msgstr "&Imagebestand..." +msgid "&Image…" +msgstr "&Imagebestand…" -msgid "E&xport to 86F..." -msgstr "E&xporteer naar 86F..." +msgid "E&xport to 86F…" +msgstr "E&xporteer naar 86F…" msgid "&Mute" msgstr "&Dempen" @@ -270,8 +291,8 @@ msgstr "&Leeg" msgid "Reload previous image" msgstr "Herlaad vorig imagebestand" -msgid "&Folder..." -msgstr "&Map..." +msgid "&Folder…" +msgstr "&Map…" msgid "Preferences" msgstr "Voorkeuren" @@ -417,17 +438,17 @@ msgstr "Joystick:" msgid "Joystick" msgstr "Joystick" -msgid "Joystick 1..." -msgstr "Joystick 1..." +msgid "Joystick 1…" +msgstr "Joystick 1…" -msgid "Joystick 2..." -msgstr "Joystick 2..." +msgid "Joystick 2…" +msgstr "Joystick 2…" -msgid "Joystick 3..." -msgstr "Joystick 3..." +msgid "Joystick 3…" +msgstr "Joystick 3…" -msgid "Joystick 4..." -msgstr "Joystick 4..." +msgid "Joystick 4…" +msgstr "Joystick 4…" msgid "Sound card #1:" msgstr "Geluidskaart #1:" @@ -516,10 +537,10 @@ msgstr "Parallelle poort 3" msgid "Parallel port 4" msgstr "Parallelle poort 4" -msgid "FD Controller:" -msgstr "FD-Controller:" +msgid "Floppy disk controller:" +msgstr "Floppy disk controller:" -msgid "CD-ROM Controller:" +msgid "CD-ROM controller:" msgstr "CD-ROM controller:" msgid "Tertiary IDE Controller" @@ -528,11 +549,11 @@ msgstr "Tertiaire IDE-controller" msgid "Quaternary IDE Controller" msgstr "Quaternaire IDE-controller" -msgid "Hard disk" -msgstr "Harde schijf" +msgid "Hard disk controllers" +msgstr "Harde schijfcontrollers" -msgid "SCSI" -msgstr "SCSI" +msgid "SCSI controllers" +msgstr "SCSI-controllers" msgid "Controller 1:" msgstr "Controller 1:" @@ -555,11 +576,11 @@ msgstr "Harde schijven:" msgid "Firmware Version" msgstr "Firmware Versie" -msgid "&New..." -msgstr "&Nieuw..." +msgid "&New…" +msgstr "&Nieuw…" -msgid "&Existing..." -msgstr "&Bestaande..." +msgid "&Existing…" +msgstr "&Bestaande…" msgid "&Remove" msgstr "&Verwijderen" @@ -867,9 +888,6 @@ msgstr "4-knops gamepad" msgid "6-button gamepad" msgstr "6-knops gamepad" -msgid "Gravis PC GamePad" -msgstr "Gravis PC GamePad" - msgid "2-button flight yoke" msgstr "2-knops stuurknuppel" @@ -897,51 +915,6 @@ msgstr "Stuurwiel (3 assen, 3 knoppen)" msgid "Steering wheel (3-axis, 4-button)" msgstr "Stuurwiel (3 assen, 4 knoppen)" -msgid "CH Flightstick" -msgstr "CH Flightstick" - -msgid "CH Flightstick + CH Pedals" -msgstr "CH Flightstick + CH Pedalen" - -msgid "CH Flightstick + CH Pedals Pro" -msgstr "CH Flightstick + CH Pedalen Pro" - -msgid "CH Flightstick Pro" -msgstr "CH Flightstick Pro" - -msgid "CH Flightstick Pro + CH Pedals" -msgstr "CH Flightstick Pro + CH Pedalen" - -msgid "CH Flightstick Pro + CH Pedals Pro" -msgstr "CH Flightstick Pro + CH Pedalen Pro" - -msgid "CH Virtual Pilot" -msgstr "CH Virtual Pilot" - -msgid "CH Virtual Pilot + CH Pedals" -msgstr "CH Virtual Pilot + CH Pedalen" - -msgid "CH Virtual Pilot + CH Pedals Pro" -msgstr "CH Virtual Pilot + CH Pedalen Pro" - -msgid "CH Virtual Pilot Pro" -msgstr "CH Virtual Pilot Pro" - -msgid "CH Virtual Pilot Pro + CH Pedals" -msgstr "CH Virtual Pilot Pro + CH Pedalen" - -msgid "CH Virtual Pilot Pro + CH Pedals Pro" -msgstr "CH Virtual Pilot Pro + CH Pedalen Pro" - -msgid "Microsoft SideWinder Pad" -msgstr "Microsoft SideWinder Pad" - -msgid "Thrustmaster Flight Control System" -msgstr "Thrustmaster Flight Control systeem" - -msgid "Thrustmaster FCS + Rudder Control System" -msgstr "Thrustmaster FCS + Roer Control Systeem" - msgid "Thrustmaster Formula T1/T2 with adapter" msgstr "Thrustmaster Formula T1/T2 met adapter" @@ -996,11 +969,17 @@ msgstr "Intern apparaat" msgid "&File" msgstr "&Bestand" -msgid "&New machine..." -msgstr "&Nieuwe machine..." +msgid "&New machine…" +msgstr "&Nieuwe machine…" + +msgid "New machine…" +msgstr "Nieuwe machine…" + +msgid "New machine" +msgstr "Nieuwe machine" -msgid "&Check for updates..." -msgstr "&Controleren op updates..." +msgid "&Check for updates…" +msgstr "&Controleren op updates…" msgid "Exit" msgstr "&Afsluiten" @@ -1170,8 +1149,8 @@ msgstr "Openen van geselecteerd configuratiebestand voor lezen niet mogelijk: %1 msgid "Use regular expressions in search box" msgstr "Gebruik reguliere expressies in zoekveld" -msgid "%1 machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" -msgstr "%1 machine(s) zijn nu actief. Weet je zeker dat je de VM manager wil afsluiten?" +msgid "%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" +msgstr "%n machine(s) zijn nu actief. Weet je zeker dat je de VM manager wil afsluiten?" msgid "Add new system wizard" msgstr "Wizard toevoegen van nieuw systeem" @@ -1251,26 +1230,23 @@ msgstr "Weergavenaam instellen" msgid "Enter the new display name (blank to reset)" msgstr "Voer een nieuwe weergavenaam in (laat leeg om te herstellen)" -msgid "Change &display name..." -msgstr "Pas &weergavenaam aan..." +msgid "Change &display name…" +msgstr "Pas &weergavenaam aan…" -msgid "Context Menu" -msgstr "Contextmenu" +msgid "&Open folder…" +msgstr "&Open map…" -msgid "&Open folder..." -msgstr "&Open map..." +msgid "Open p&rinter tray…" +msgstr "Open &papierlade…" -msgid "Open p&rinter tray..." -msgstr "Open &papierlade..." - -msgid "Set &icon..." -msgstr "Stel &icoon in..." +msgid "Set &icon…" +msgstr "Stel &icoon in…" msgid "Select an icon" msgstr "Selecteer een icoon" -msgid "C&lone..." -msgstr "K&lonen..." +msgid "C&lone…" +msgstr "K&lonen…" msgid "Virtual machine \"%1\" (%2) will be cloned into:" msgstr "Virtuele machine \"%1\" (%2) zal gekloond worden naar:" @@ -1356,8 +1332,8 @@ msgstr "Geen schermafbeelding" msgid "Search" msgstr "Zoeken" -msgid "Searching for VMs..." -msgstr "Zoeken naar VMs..." +msgid "Searching for VMs…" +msgstr "Zoeken naar VMs…" msgid "Found %1" msgstr "Gevonden %1" @@ -1392,11 +1368,11 @@ msgstr "Harde schijf (%1)" msgid "MFM/RLL or ESDI CD-ROM drives never existed" msgstr "MFM/RLL of ESDI CD-ROM-stations hebben nooit bestaan" -msgid "Custom..." -msgstr "Aangepast..." +msgid "Custom…" +msgstr "Aangepast…" -msgid "Custom (large)..." -msgstr "Aangepast (groot)..." +msgid "Custom (large)…" +msgstr "Aangepast (groot)…" msgid "Add New Hard Disk" msgstr "Nieuwe harde schijf toevoegen" @@ -1515,21 +1491,6 @@ msgstr "Bovenliggende en onderliggende schijftijdstempels komen niet overeen" msgid "Could not fix VHD timestamp." msgstr "Kan VHD tijdstempel niet herstellen." -msgid "MFM/RLL" -msgstr "MFM/RLL" - -msgid "XTA" -msgstr "XTA" - -msgid "ESDI" -msgstr "ESDI" - -msgid "IDE" -msgstr "IDE" - -msgid "ATAPI" -msgstr "ATAPI" - msgid "CD-ROM %1 (%2): %3" msgstr "CD-ROM %1 (%2): %3" @@ -1680,14 +1641,14 @@ msgstr "&Tablet-hulpmiddel" msgid "About &Qt" msgstr "Over &Qt" -msgid "&MCA devices..." -msgstr "MCA-apparaten..." +msgid "&MCA devices…" +msgstr "MCA-apparaten…" msgid "Show non-&primary monitors" msgstr "Toon niet-primaire beeldschermen" -msgid "Open screenshots &folder..." -msgstr "&Map met schermafbeeldingen openen..." +msgid "Open screenshots &folder…" +msgstr "&Map met schermafbeeldingen openen…" msgid "Appl&y fullscreen stretch mode when maximized" msgstr "Schakel de volledig scherm-uitrekmodus in bij maximaliseren" @@ -1707,8 +1668,8 @@ msgstr "&Verbonden" msgid "Clear image &history" msgstr "Imagegeschiedenis verwijderen(&H)" -msgid "Create..." -msgstr "Aanmaken..." +msgid "Create…" +msgstr "Aanmaken…" msgid "Host CD/DVD Drive (%1)" msgstr "Host CD/DVD-station (%1)" @@ -1749,8 +1710,8 @@ msgstr "Shaders" msgid "Remove" msgstr "Verwijderen" -msgid "Browse..." -msgstr "Bladeren..." +msgid "Browse…" +msgstr "Bladeren…" msgid "Couldn't create OpenGL context." msgstr "Kan OpenGL-context niet aanmaken." @@ -1839,8 +1800,8 @@ msgstr "Seriële poort doorvoer 3" msgid "Serial port passthrough 4" msgstr "Seriële poort doorvoer 4" -msgid "Renderer &options..." -msgstr "Renderer-opties..." +msgid "Renderer &options…" +msgstr "Renderer-opties…" msgid "PC/XT Keyboard" msgstr "PC/XT Toetsenbord" @@ -1893,8 +1854,8 @@ msgstr "3M MicroTouch (serieel)" msgid "Default Baud rate" msgstr "Standaard baudrate" -msgid "[COM] Standard Hayes-compliant Modem" -msgstr "[COM] Standaard Hayes-compatibele modem" +msgid "Standard Hayes-compliant Modem" +msgstr "Standaard Hayes-compatibele modem" msgid "Roland MT-32 Emulation" msgstr "Roland MT-32-emulatie" @@ -1977,6 +1938,9 @@ msgstr "Seriële poort IRQ" msgid "Parallel port IRQ" msgstr "Parallelle poort IRQ" +msgid "Hard disk" +msgstr "Harde schijf" + msgid "BIOS Revision" msgstr "BIOS-Revisie" @@ -2052,9 +2016,6 @@ msgstr "MIDI doorvoer" msgid "MIDI Clockout" msgstr "MIDI Clockout" -msgid "SoundFont" -msgstr "SoundFont" - msgid "Output Gain" msgstr "Output Gain" @@ -2847,9 +2808,6 @@ msgstr "Volledig scherm omschakelen" msgid "Toggle UI in fullscreen" msgstr "" -msgid "Screenshot" -msgstr "Schermafbeelding" - msgid "Release mouse pointer" msgstr "Geef muis vrij" @@ -2964,8 +2922,8 @@ msgstr "Bezoek downloadpagina" msgid "Update check" msgstr "Updatecontrole" -msgid "Checking for updates..." -msgstr "Controleren op updates..." +msgid "Checking for updates…" +msgstr "Controleren op updates…" msgid "86Box Update" msgstr "86Box Update" @@ -3003,8 +2961,8 @@ msgstr "Helderheid" msgid "Sharpness" msgstr "Scherpte" -msgid "&CGA composite settings..." -msgstr "Instellingen van de &CGA-compositemodus..." +msgid "&CGA composite settings…" +msgstr "Instellingen van de &CGA-compositemodus…" msgid "CGA composite settings" msgstr "Instellingen van de CGA-compositemodus" @@ -3012,8 +2970,8 @@ msgstr "Instellingen van de CGA-compositemodus" msgid "Monitor EDID" msgstr "EDID-monitor" -msgid "Export..." -msgstr "Exporteren..." +msgid "Export…" +msgstr "Exporteren…" msgid "Export EDID" msgstr "EDID exporteren" @@ -3038,3 +2996,24 @@ msgstr "Donker" msgid "Search:" msgstr "Zoeken:" + +msgid "Force interpretation" +msgstr "Interpretatie afdwingen" + +msgid "Allow recompilation" +msgstr "Recompilatie toestaan" + +msgid "&Force interpretation" +msgstr "Interpretatie &afdwingen" + +msgid "&Allow recompilation" +msgstr "Recompilatie &toestaan" + +msgid "&Fast forward" +msgstr "" + +msgid "Fast forward" +msgstr "" + +msgid "To change the system directory, stop all running machines." +msgstr "" diff --git a/src/qt/languages/pl-PL.po b/src/qt/languages/pl-PL.po index ae47844c256..20317c9eccc 100644 --- a/src/qt/languages/pl-PL.po +++ b/src/qt/languages/pl-PL.po @@ -73,8 +73,8 @@ msgstr "Open&GL (3.0 Core)" msgid "&VNC" msgstr "&VNC" -msgid "Specify &dimensions..." -msgstr "Określ wymiary..." +msgid "Specify &dimensions…" +msgstr "Określ wymiary…" msgid "Force &4:3 display ratio" msgstr "Wymuś proporcje wyświetlania &4:3" @@ -199,11 +199,11 @@ msgstr "N&ośnik" msgid "&Tools" msgstr "&Narzędzia" -msgid "&Settings..." -msgstr "&Ustawienia..." +msgid "&Settings…" +msgstr "&Ustawienia…" -msgid "Settings..." -msgstr "Ustawienia..." +msgid "Settings…" +msgstr "Ustawienia…" msgid "&Update status bar icons" msgstr "&Aktualizuj ikony na pasku statusu" @@ -211,17 +211,38 @@ msgstr "&Aktualizuj ikony na pasku statusu" msgid "Take s&creenshot" msgstr "Zrób &zrzut ekranu" +msgid "Take screenshot" +msgstr "Zrób zrzut ekranu" + +msgid "Take &raw screenshot" +msgstr "Zrób &surowy zrzut ekranu" + +msgid "Take raw screenshot" +msgstr "Zrób surowy zrzut ekranu" + +msgid "C&opy screenshot" +msgstr "S&kopiuj zrzut ekranu" + +msgid "Copy screenshot" +msgstr "Skopiuj zrzut ekranu" + +msgid "Copy r&aw screenshot" +msgstr "Skopiuj s&urowy zrzut ekranu" + +msgid "Copy raw screenshot" +msgstr "Skopiuj surowy zrzut ekranu" + msgid "S&ound" msgstr "Dź&więk" -msgid "&Preferences..." -msgstr "&Preferencje..." +msgid "&Preferences…" +msgstr "&Preferencje…" msgid "Enable &Discord integration" msgstr "Włącz integrację z &Discordem" -msgid "Sound &gain..." -msgstr "Wzmocnienie &dźwięku..." +msgid "Sound &gain…" +msgstr "Wzmocnienie &dźwięku…" msgid "Begin trace" msgstr "Rozpocznij śledzenie" @@ -232,20 +253,20 @@ msgstr "Zakończ śledzenie" msgid "&Help" msgstr "Pomo&c" -msgid "&Documentation..." -msgstr "&Dokumentacja..." +msgid "&Documentation…" +msgstr "&Dokumentacja…" -msgid "&About 86Box..." -msgstr "&O 86Boxie..." +msgid "&About 86Box…" +msgstr "&O 86Boxie…" -msgid "&New image..." -msgstr "&Nowy obraz..." +msgid "&New image…" +msgstr "&Nowy obraz…" -msgid "&Existing image..." -msgstr "&Istniejący obraz..." +msgid "&Existing image…" +msgstr "&Istniejący obraz…" -msgid "Existing image (&Write-protected)..." -msgstr "Istniejący obraz (&Chroniony przed zapisem)..." +msgid "Existing image (&Write-protected)…" +msgstr "Istniejący obraz (&Chroniony przed zapisem)…" msgid "&Record" msgstr "&Nagraj" @@ -262,11 +283,11 @@ msgstr "&Przewiń do końca" msgid "E&ject" msgstr "W&yjmij" -msgid "&Image..." -msgstr "&Obraz..." +msgid "&Image…" +msgstr "&Obraz…" -msgid "E&xport to 86F..." -msgstr "E&ksportuj do 86F..." +msgid "E&xport to 86F…" +msgstr "E&ksportuj do 86F…" msgid "&Mute" msgstr "&Wycisz" @@ -277,8 +298,8 @@ msgstr "P&usty" msgid "Reload previous image" msgstr "Przeładuj poprzedni obraz" -msgid "&Folder..." -msgstr "&Folder..." +msgid "&Folder…" +msgstr "&Folder…" msgid "Preferences" msgstr "Preferencje" @@ -424,17 +445,17 @@ msgstr "Joystick:" msgid "Joystick" msgstr "Joystick" -msgid "Joystick 1..." -msgstr "Joystick 1..." +msgid "Joystick 1…" +msgstr "Joystick 1…" -msgid "Joystick 2..." -msgstr "Joystick 2..." +msgid "Joystick 2…" +msgstr "Joystick 2…" -msgid "Joystick 3..." -msgstr "Joystick 3..." +msgid "Joystick 3…" +msgstr "Joystick 3…" -msgid "Joystick 4..." -msgstr "Joystick 4..." +msgid "Joystick 4…" +msgstr "Joystick 4…" msgid "Sound card #1:" msgstr "Karta dźwiękowa nr 1:" @@ -523,10 +544,10 @@ msgstr "Port równoległy 3" msgid "Parallel port 4" msgstr "Port równoległy 4" -msgid "FD Controller:" +msgid "Floppy disk controller:" msgstr "Kontroler dyskietek:" -msgid "CD-ROM Controller:" +msgid "CD-ROM controller:" msgstr "Kontroler CD-ROM:" msgid "Tertiary IDE Controller" @@ -535,11 +556,11 @@ msgstr "Trzeciorzędny kontroler IDE" msgid "Quaternary IDE Controller" msgstr "Czwartorzędny kontroler IDE" -msgid "Hard disk" -msgstr "Dysk twardy" +msgid "Hard disk controllers" +msgstr "Kontrolery dysków twardych" -msgid "SCSI" -msgstr "SCSI" +msgid "SCSI controllers" +msgstr "Kontrolery SCSI" msgid "Controller 1:" msgstr "Kontroler 1:" @@ -562,11 +583,11 @@ msgstr "Dyski twarde:" msgid "Firmware Version" msgstr "Wersja firmware'u" -msgid "&New..." -msgstr "&Nowy..." +msgid "&New…" +msgstr "&Nowy…" -msgid "&Existing..." -msgstr "&Istniejący..." +msgid "&Existing…" +msgstr "&Istniejący…" msgid "&Remove" msgstr "&Usuń" @@ -874,9 +895,6 @@ msgstr "Pad z czterema przyciskami" msgid "6-button gamepad" msgstr "Pad z sześcioma przyciskami" -msgid "Gravis PC GamePad" -msgstr "Gravis PC GamePad" - msgid "2-button flight yoke" msgstr "Wolant z dwoma przyciskami" @@ -904,51 +922,6 @@ msgstr "Kierownica (3 osie, 3 przyciski)" msgid "Steering wheel (3-axis, 4-button)" msgstr "Kierownica (3 osie, 4 przyciski)" -msgid "CH Flightstick" -msgstr "CH Flightstick" - -msgid "CH Flightstick + CH Pedals" -msgstr "CH Flightstick + CH Pedals" - -msgid "CH Flightstick + CH Pedals Pro" -msgstr "CH Flightstick + CH Pedals Pro" - -msgid "CH Flightstick Pro" -msgstr "CH Flightstick Pro" - -msgid "CH Flightstick Pro + CH Pedals" -msgstr "CH Flightstick Pro + CH Pedals" - -msgid "CH Flightstick Pro + CH Pedals Pro" -msgstr "CH Flightstick Pro + CH Pedals Pro" - -msgid "CH Virtual Pilot" -msgstr "CH Virtual Pilot" - -msgid "CH Virtual Pilot + CH Pedals" -msgstr "CH Virtual Pilot + CH Pedals" - -msgid "CH Virtual Pilot + CH Pedals Pro" -msgstr "CH Virtual Pilot + CH Pedals Pro" - -msgid "CH Virtual Pilot Pro" -msgstr "CH Virtual Pilot Pro" - -msgid "CH Virtual Pilot Pro + CH Pedals" -msgstr "CH Virtual Pilot Pro + CH Pedals" - -msgid "CH Virtual Pilot Pro + CH Pedals Pro" -msgstr "CH Virtual Pilot Pro + CH Pedals Pro" - -msgid "Microsoft SideWinder Pad" -msgstr "Microsoft SideWinder Pad" - -msgid "Thrustmaster Flight Control System" -msgstr "Thrustmaster Flight Control System" - -msgid "Thrustmaster FCS + Rudder Control System" -msgstr "Thrustmaster FCS + Rudder Control System" - msgid "Thrustmaster Formula T1/T2 with adapter" msgstr "Thrustmaster Formula T1/T2 z adapterem" @@ -1003,11 +976,17 @@ msgstr "Urządzenie wewnętrzne" msgid "&File" msgstr "&Plik" -msgid "&New machine..." -msgstr "&Nowa maszyna..." +msgid "&New machine…" +msgstr "&Nowa maszyna…" + +msgid "New machine…" +msgstr "Nowa maszyna…" + +msgid "New machine" +msgstr "Nowa maszyna" -msgid "&Check for updates..." -msgstr "&Sprawdź aktualizacje..." +msgid "&Check for updates…" +msgstr "&Sprawdź aktualizacje…" msgid "Exit" msgstr "Za&kończ" @@ -1177,8 +1156,8 @@ msgstr "Nie udało się otworzyć wybranego pliku konfiguracyjnego do odczytu: % msgid "Use regular expressions in search box" msgstr "Użyj wyrażeń regularnych w polu wyszukiwania" -msgid "%1 machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" -msgstr "Liczba obecnie aktywnych maszyn: %1. Czy na pewno chcesz, mimo to, wyjść z menedżera maszyn wirtualnych?" +msgid "%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" +msgstr "Liczba obecnie aktywnych maszyn: %n. Czy na pewno chcesz, mimo to, wyjść z menedżera maszyn wirtualnych?" msgid "Add new system wizard" msgstr "Kreator dodawania nowego systemu" @@ -1258,26 +1237,23 @@ msgstr "Ustaw nazwę wyświetlaną" msgid "Enter the new display name (blank to reset)" msgstr "Podaj nową nazwę wyświetlaną (wyczyść, by zresetować)" -msgid "Change &display name..." -msgstr "Zmień wyświetlaną &nazwę..." +msgid "Change &display name…" +msgstr "Zmień wyświetlaną &nazwę…" -msgid "Context Menu" -msgstr "Menu kontekstowe" +msgid "&Open folder…" +msgstr "&Otwórz folder…" -msgid "&Open folder..." -msgstr "&Otwórz folder..." +msgid "Open p&rinter tray…" +msgstr "Otwórz &tackę drukarki…" -msgid "Open p&rinter tray..." -msgstr "Otwórz &tackę drukarki..." - -msgid "Set &icon..." -msgstr "&Ustaw ikonę..." +msgid "Set &icon…" +msgstr "&Ustaw ikonę…" msgid "Select an icon" msgstr "Wybierz ikonę" -msgid "C&lone..." -msgstr "&Klonuj..." +msgid "C&lone…" +msgstr "&Klonuj…" msgid "Virtual machine \"%1\" (%2) will be cloned into:" msgstr "Maszyna wirtualna „%1” (%2) zostanie sklonowana jako:" @@ -1363,8 +1339,8 @@ msgstr "Brak zrzutów ekranu" msgid "Search" msgstr "Szukanie" -msgid "Searching for VMs..." -msgstr "Szukanie maszyn wirtualnych..." +msgid "Searching for VMs…" +msgstr "Szukanie maszyn wirtualnych…" msgid "Found %1" msgstr "Znaleziono %1" @@ -1399,11 +1375,11 @@ msgstr "Dysk twardy (%1)" msgid "MFM/RLL or ESDI CD-ROM drives never existed" msgstr "Napędy CD-ROM MFM/RLL lub ESDI nigdy nie istniały" -msgid "Custom..." -msgstr "Niestandardowy..." +msgid "Custom…" +msgstr "Niestandardowy…" -msgid "Custom (large)..." -msgstr "Niestandardowy (duży)..." +msgid "Custom (large)…" +msgstr "Niestandardowy (duży)…" msgid "Add New Hard Disk" msgstr "Dodaj nowy dysk twardy" @@ -1522,21 +1498,6 @@ msgstr "Sygnatury czasowe dysku nadrzędnego i podrzędnego nie zgadzają się" msgid "Could not fix VHD timestamp." msgstr "Nie można naprawić sygnatury czasowej VHD." -msgid "MFM/RLL" -msgstr "MFM/RLL" - -msgid "XTA" -msgstr "XTA" - -msgid "ESDI" -msgstr "ESDI" - -msgid "IDE" -msgstr "IDE" - -msgid "ATAPI" -msgstr "ATAPI" - msgid "CD-ROM %1 (%2): %3" msgstr "CD-ROM %1 (%2): %3" @@ -1687,14 +1648,14 @@ msgstr "Narzędzie do tabletów" msgid "About &Qt" msgstr "O &Qt" -msgid "&MCA devices..." -msgstr "Urządzenia MCA..." +msgid "&MCA devices…" +msgstr "Urządzenia MCA…" msgid "Show non-&primary monitors" msgstr "Pokaż monitory &inne niż podstawowe" -msgid "Open screenshots &folder..." -msgstr "Otwórz folder zrzutów &ekranu..." +msgid "Open screenshots &folder…" +msgstr "Otwórz folder zrzutów &ekranu…" msgid "Appl&y fullscreen stretch mode when maximized" msgstr "Zastosowanie trybu rozciągania na pełnym ekranie w stanie zmaksymalizowanym" @@ -1714,8 +1675,8 @@ msgstr "&Podłączone" msgid "Clear image &history" msgstr "Wyczyść historię obrazów(&H)" -msgid "Create..." -msgstr "Stwórz..." +msgid "Create…" +msgstr "Stwórz…" msgid "Host CD/DVD Drive (%1)" msgstr "Napęd CD/DVD hosta (%1)" @@ -1756,8 +1717,8 @@ msgstr "Shadery" msgid "Remove" msgstr "Usuń" -msgid "Browse..." -msgstr "Przeglądaj..." +msgid "Browse…" +msgstr "Przeglądaj…" msgid "Couldn't create OpenGL context." msgstr "Nie można utworzyć kontekstu OpenGL." @@ -1846,8 +1807,8 @@ msgstr "Przelotka portu szeregowego 3" msgid "Serial port passthrough 4" msgstr "Przelotka portu szeregowego 4" -msgid "Renderer &options..." -msgstr "Opcje renderowania..." +msgid "Renderer &options…" +msgstr "Opcje renderowania…" msgid "PC/XT Keyboard" msgstr "Klawiatura PC/XT" @@ -1900,8 +1861,8 @@ msgstr "3M MicroTouch (szeregowy)" msgid "Default Baud rate" msgstr "Domyślna szybkość transmisji" -msgid "[COM] Standard Hayes-compliant Modem" -msgstr "[COM] Standardowy modem zgodny z Hayes" +msgid "Standard Hayes-compliant Modem" +msgstr "Standardowy modem zgodny z Hayes" msgid "Roland MT-32 Emulation" msgstr "Emulacja Roland MT-32" @@ -1984,6 +1945,9 @@ msgstr "IRQ portu szeregowego" msgid "Parallel port IRQ" msgstr "IRQ portu równoległego" +msgid "Hard disk" +msgstr "Dysk twardy" + msgid "BIOS Revision" msgstr "Rewizja BIOS-u" @@ -2059,9 +2023,6 @@ msgstr "Przejście wejścia MIDI" msgid "MIDI Clockout" msgstr "Wyjście zegara MIDI" -msgid "SoundFont" -msgstr "SoundFont" - msgid "Output Gain" msgstr "Wzmocnienie wyjściowe" @@ -2854,9 +2815,6 @@ msgstr "Przełącz pełny ekran" msgid "Toggle UI in fullscreen" msgstr "Przełącz UI w pełnym ekranie" -msgid "Screenshot" -msgstr "Zrzut ekranu" - msgid "Release mouse pointer" msgstr "Wypuść wskaźnik myszy" @@ -2971,8 +2929,8 @@ msgstr "Odwiedź stronę pobierania" msgid "Update check" msgstr "Sprawdzanie aktualizacji" -msgid "Checking for updates..." -msgstr "Sprawdzanie aktualizacji..." +msgid "Checking for updates…" +msgstr "Sprawdzanie aktualizacji…" msgid "86Box Update" msgstr "Aktualizacja 86Boxa" @@ -3010,8 +2968,8 @@ msgstr "Jasność" msgid "Sharpness" msgstr "Ostrość" -msgid "&CGA composite settings..." -msgstr "Ustawienia trybu kompozytowego &CGA..." +msgid "&CGA composite settings…" +msgstr "Ustawienia trybu kompozytowego &CGA…" msgid "CGA composite settings" msgstr "Ustawienia trybu kompozytowego CGA" @@ -3019,8 +2977,8 @@ msgstr "Ustawienia trybu kompozytowego CGA" msgid "Monitor EDID" msgstr "EDID monitora" -msgid "Export..." -msgstr "Eksportuj..." +msgid "Export…" +msgstr "Eksportuj…" msgid "Export EDID" msgstr "Eksportuj EDID" @@ -3045,3 +3003,24 @@ msgstr "Ciemny" msgid "Search:" msgstr "Szukanie:" + +msgid "Force interpretation" +msgstr "Wymuś interpretację" + +msgid "Allow recompilation" +msgstr "Zezwól na rekompilację" + +msgid "&Force interpretation" +msgstr "&Wymuś interpretację" + +msgid "&Allow recompilation" +msgstr "&Zezwól na rekompilację" + +msgid "&Fast forward" +msgstr "" + +msgid "Fast forward" +msgstr "" + +msgid "To change the system directory, stop all running machines." +msgstr "" diff --git a/src/qt/languages/pt-BR.po b/src/qt/languages/pt-BR.po index d8fddc787fa..31875d7bab0 100644 --- a/src/qt/languages/pt-BR.po +++ b/src/qt/languages/pt-BR.po @@ -66,8 +66,8 @@ msgstr "Open&GL (Núcleo 3.0)" msgid "&VNC" msgstr "&VNC" -msgid "Specify &dimensions..." -msgstr "Especificar as dime&nsões..." +msgid "Specify &dimensions…" +msgstr "Especificar as dime&nsões…" msgid "Force &4:3 display ratio" msgstr "Forçar proporção de tela em &4:3" @@ -192,11 +192,11 @@ msgstr "&Mídia" msgid "&Tools" msgstr "&Ferramentas" -msgid "&Settings..." -msgstr "&Configurações..." +msgid "&Settings…" +msgstr "&Configurações…" -msgid "Settings..." -msgstr "Configurações..." +msgid "Settings…" +msgstr "Configurações…" msgid "&Update status bar icons" msgstr "&Atualizar ícones da barra de status" @@ -204,17 +204,38 @@ msgstr "&Atualizar ícones da barra de status" msgid "Take s&creenshot" msgstr "Capturar &tela" +msgid "Take screenshot" +msgstr "Capturar tela" + +msgid "Take &raw screenshot" +msgstr "Fazer captura &bruta da tela" + +msgid "Take raw screenshot" +msgstr "Fazer captura bruta da tela" + +msgid "C&opy screenshot" +msgstr "C&opiar captura da tela" + +msgid "Copy screenshot" +msgstr "Copiar captura da tela" + +msgid "Copy r&aw screenshot" +msgstr "Copiar captura b&ruta da tela" + +msgid "Copy raw screenshot" +msgstr "Copiar captura bruta da tela" + msgid "S&ound" msgstr "&Som" -msgid "&Preferences..." -msgstr "&Preferências..." +msgid "&Preferences…" +msgstr "&Preferências…" msgid "Enable &Discord integration" msgstr "Ativar integração com o &Discord" -msgid "Sound &gain..." -msgstr "&Ganho de som..." +msgid "Sound &gain…" +msgstr "&Ganho de som…" msgid "Begin trace" msgstr "Inicio do rastreamento" @@ -225,20 +246,20 @@ msgstr "Finalizar rastreamento" msgid "&Help" msgstr "Aj&uda" -msgid "&Documentation..." -msgstr "&Documentação..." +msgid "&Documentation…" +msgstr "&Documentação…" -msgid "&About 86Box..." -msgstr "&Sobre o 86Box..." +msgid "&About 86Box…" +msgstr "&Sobre o 86Box…" -msgid "&New image..." -msgstr "&Nova imagem..." +msgid "&New image…" +msgstr "&Nova imagem…" -msgid "&Existing image..." -msgstr "&Imagem existente..." +msgid "&Existing image…" +msgstr "&Imagem existente…" -msgid "Existing image (&Write-protected)..." -msgstr "Imagem existente (&protegida contra gravação)..." +msgid "Existing image (&Write-protected)…" +msgstr "Imagem existente (&protegida contra gravação)…" msgid "&Record" msgstr "&Gravar" @@ -255,11 +276,11 @@ msgstr "&Avançar até o fim" msgid "E&ject" msgstr "E&jetar" -msgid "&Image..." -msgstr "&Imagem..." +msgid "&Image…" +msgstr "&Imagem…" -msgid "E&xport to 86F..." -msgstr "E&xportar para 86F..." +msgid "E&xport to 86F…" +msgstr "E&xportar para 86F…" msgid "&Mute" msgstr "&Silenciar" @@ -270,8 +291,8 @@ msgstr "&Vazio" msgid "Reload previous image" msgstr "Recarregar imagem anterior" -msgid "&Folder..." -msgstr "&Pasta..." +msgid "&Folder…" +msgstr "&Pasta…" msgid "Preferences" msgstr "Preferências" @@ -280,7 +301,7 @@ msgid "Sound Gain" msgstr "Ganho de som" msgid "New Image" -msgstr "Nova imagem de disquete" +msgstr "Nova imagem" msgid "Settings" msgstr "Configurações" @@ -358,7 +379,7 @@ msgid "Memory:" msgstr "Memória:" msgid "Time synchronization" -msgstr "Sincronização de hora" +msgstr "Sincronização de horário" msgid "Disabled" msgstr "Desativar" @@ -417,17 +438,17 @@ msgstr "Joystick:" msgid "Joystick" msgstr "Joystick" -msgid "Joystick 1..." -msgstr "Joystick 1..." +msgid "Joystick 1…" +msgstr "Joystick 1…" -msgid "Joystick 2..." -msgstr "Joystick 2..." +msgid "Joystick 2…" +msgstr "Joystick 2…" -msgid "Joystick 3..." -msgstr "Joystick 3..." +msgid "Joystick 3…" +msgstr "Joystick 3…" -msgid "Joystick 4..." -msgstr "Joystick 4..." +msgid "Joystick 4…" +msgstr "Joystick 4…" msgid "Sound card #1:" msgstr "Placa de som nº 1:" @@ -516,10 +537,10 @@ msgstr "Porta paralela 3" msgid "Parallel port 4" msgstr "Porta paralela 4" -msgid "FD Controller:" +msgid "Floppy disk controller:" msgstr "Controlador de disquete:" -msgid "CD-ROM Controller:" +msgid "CD-ROM controller:" msgstr "Controlador de CD-ROM:" msgid "Tertiary IDE Controller" @@ -528,11 +549,11 @@ msgstr "Controlador IDE terciário" msgid "Quaternary IDE Controller" msgstr "Controlador IDE quaternário" -msgid "Hard disk" -msgstr "Disco rígido" +msgid "Hard disk controllers" +msgstr "Controladores de disco rígido" -msgid "SCSI" -msgstr "SCSI" +msgid "SCSI controllers" +msgstr "Controladores SCSI" msgid "Controller 1:" msgstr "Controlador 1:" @@ -555,11 +576,11 @@ msgstr "Discos rígidos:" msgid "Firmware Version" msgstr "Versão do Firmware" -msgid "&New..." -msgstr "&Novo..." +msgid "&New…" +msgstr "&Novo…" -msgid "&Existing..." -msgstr "&Existente..." +msgid "&Existing…" +msgstr "&Existente…" msgid "&Remove" msgstr "&Remover" @@ -820,7 +841,7 @@ msgid "Generic paddle controller(s)" msgstr "Controlador(es) genérico(s) de raquete" msgid "2-axis, 1-button joystick(s)" -msgstr "Joystick(s) de 2 eixos, 1 botões" +msgstr "Joystick(s) de 2 eixos, 1 botão" msgid "2-axis, 2-button joystick(s)" msgstr "Joystick(s) de 2 eixos, 2 botões" @@ -867,9 +888,6 @@ msgstr "Gamepad de 4 botões" msgid "6-button gamepad" msgstr "Gamepad de 6 botões" -msgid "Gravis PC GamePad" -msgstr "GamePad Gravis PC" - msgid "2-button flight yoke" msgstr "Manche de voo de 2 botões" @@ -897,51 +915,6 @@ msgstr "Volante (3 eixos, 3 botões)" msgid "Steering wheel (3-axis, 4-button)" msgstr "Volante (3 eixos, 4 botões)" -msgid "CH Flightstick" -msgstr "CH Flightstick" - -msgid "CH Flightstick + CH Pedals" -msgstr "CH Flightstick + Pedais CH" - -msgid "CH Flightstick + CH Pedals Pro" -msgstr "CH Flightstick + Pedais CH Pro" - -msgid "CH Flightstick Pro" -msgstr "CH Flightstick Pro" - -msgid "CH Flightstick Pro + CH Pedals" -msgstr "CH Flightstick Pro + Pedais CH" - -msgid "CH Flightstick Pro + CH Pedals Pro" -msgstr "CH Flightstick Pro + Pedais CH Pro" - -msgid "CH Virtual Pilot" -msgstr "CH Virtual Pilot" - -msgid "CH Virtual Pilot + CH Pedals" -msgstr "CH Virtual Pilot + Pedais CH" - -msgid "CH Virtual Pilot + CH Pedals Pro" -msgstr "CH Virtual Pilot + Pedais CH Pro" - -msgid "CH Virtual Pilot Pro" -msgstr "CH Virtual Pilot Pro" - -msgid "CH Virtual Pilot Pro + CH Pedals" -msgstr "CH Virtual Pilot Pro + Pedais CH" - -msgid "CH Virtual Pilot Pro + CH Pedals Pro" -msgstr "CH Virtual Pilot Pro + Pedais CH Pro" - -msgid "Microsoft SideWinder Pad" -msgstr "Microsoft SideWinder Pad" - -msgid "Thrustmaster Flight Control System" -msgstr "Sistema de Controle de Voo Thrustmaster" - -msgid "Thrustmaster FCS + Rudder Control System" -msgstr "SCV Thrustmaster + Sistema de Controle de Leme" - msgid "Thrustmaster Formula T1/T2 with adapter" msgstr "Thrustmaster Formula T1/T2 com adaptador" @@ -961,7 +934,7 @@ msgid "&Floppy %1 (%2): %3" msgstr "&Disquete %1 (%2): %3" msgid "Advanced sector images" -msgstr "Imagens de setor avançado" +msgstr "Imagens de setor avançadas" msgid "Flux images" msgstr "Imagens de fluxo" @@ -996,11 +969,17 @@ msgstr "Dispositivo interno" msgid "&File" msgstr "&Arquivo" -msgid "&New machine..." -msgstr "&Nova máquina..." +msgid "&New machine…" +msgstr "&Nova máquina…" + +msgid "New machine…" +msgstr "Nova máquina…" + +msgid "New machine" +msgstr "Nova máquina" -msgid "&Check for updates..." -msgstr "&Verificar por atualizações..." +msgid "&Check for updates…" +msgstr "&Verificar por atualizações…" msgid "Exit" msgstr "Sair" @@ -1123,7 +1102,7 @@ msgid "Not running" msgstr "Parado" msgid "Running" -msgstr "Rodando" +msgstr "Executando" msgid "Paused" msgstr "Pausada" @@ -1170,8 +1149,8 @@ msgstr "Não foi possível abrir o arquivo de configuração selecionado para le msgid "Use regular expressions in search box" msgstr "Usar expressões regulares na caixa de pesquisa" -msgid "%1 machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" -msgstr "%1 máquina(s) estão ativas atualmente. Tem certeza que deseja encerrar o gerenciador de MV mesmo assim?" +msgid "%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" +msgstr "%n máquina(s) está(ão) ativa(s) no momento. Tem certeza de que deseja sair do gerenciador de MVs mesmo assim?" msgid "Add new system wizard" msgstr "Assistente para novo sistema" @@ -1186,7 +1165,7 @@ msgid "New configuration" msgstr "Nova configuração" msgid "Complete" -msgstr "Completado" +msgstr "Concluído" msgid "The wizard will now launch the configuration for the new system." msgstr "O assistente vai iniciar a configuração para o novo sistema." @@ -1251,26 +1230,23 @@ msgstr "Defina o nome de exibição" msgid "Enter the new display name (blank to reset)" msgstr "Digite o novo nome de exibição (em branco para restaurar)" -msgid "Change &display name..." -msgstr "Mudar o &nome de exibição..." +msgid "Change &display name…" +msgstr "Mudar o &nome de exibição…" -msgid "Context Menu" -msgstr "Menu de contexto" +msgid "&Open folder…" +msgstr "Abrir &pasta…" -msgid "&Open folder..." -msgstr "Abrir &pasta..." +msgid "Open p&rinter tray…" +msgstr "Abrir fila da &impressora…" -msgid "Open p&rinter tray..." -msgstr "Abrir fila da &impressora..." - -msgid "Set &icon..." -msgstr "&Definir ícone..." +msgid "Set &icon…" +msgstr "&Definir ícone…" msgid "Select an icon" msgstr "Selecione um ícone" -msgid "C&lone..." -msgstr "&Clonar..." +msgid "C&lone…" +msgstr "&Clonar…" msgid "Virtual machine \"%1\" (%2) will be cloned into:" msgstr "A máquina virtual \"%1\" (%2) será clonada em:" @@ -1294,7 +1270,7 @@ msgid "Directory in use" msgstr "Diretório em uso" msgid "The selected directory is already in use. Please select a different directory." -msgstr "O diretório selecionado já está em uso. Por favor escolha um diretório diferente." +msgstr "O diretório selecionado já está em uso. Por favor, escolha um diretório diferente." msgid "Create directory failed" msgstr "Falha ao criar diretório" @@ -1309,7 +1285,7 @@ msgid "Unable to open the configuration file at %1 for writing" msgstr "Impossível abrir o arquivo de configuração %1 para escrita" msgid "Error adding system" -msgstr "Erro adicionando sistema" +msgstr "Erro ao adicionar sistema" msgid "Remove directory failed" msgstr "Falha ao remover diretório" @@ -1356,11 +1332,11 @@ msgstr "Nenhuma captura de tela" msgid "Search" msgstr "Pesquisar" -msgid "Searching for VMs..." -msgstr "Procurando por MVs..." +msgid "Searching for VMs…" +msgstr "Procurando por MVs…" msgid "Found %1" -msgstr "Encontrado %1" +msgstr "Encontrada %1" msgid "System" msgstr "Sistema" @@ -1392,11 +1368,11 @@ msgstr "Disco rígido (%1)" msgid "MFM/RLL or ESDI CD-ROM drives never existed" msgstr "As unidades de CD-ROM MFM/RLL ou ESDI nunca existiram" -msgid "Custom..." -msgstr "Personalizado..." +msgid "Custom…" +msgstr "Personalizado…" -msgid "Custom (large)..." -msgstr "Personalizado (grande)..." +msgid "Custom (large)…" +msgstr "Personalizado (grande)…" msgid "Add New Hard Disk" msgstr "Adicionar novo disco rígido" @@ -1515,21 +1491,6 @@ msgstr "Os marcadores de tempo do disco pai e do disco filho não coincidem" msgid "Could not fix VHD timestamp." msgstr "Não foi possível corrigir o marcador de tempo do VHD." -msgid "MFM/RLL" -msgstr "MFM/RLL" - -msgid "XTA" -msgstr "XTA" - -msgid "ESDI" -msgstr "ESDI" - -msgid "IDE" -msgstr "IDE" - -msgid "ATAPI" -msgstr "ATAPI" - msgid "CD-ROM %1 (%2): %3" msgstr "CD-ROM %1 (%2): %3" @@ -1680,14 +1641,14 @@ msgstr "Ferramenta para &tablet" msgid "About &Qt" msgstr "Sobre o &Qt" -msgid "&MCA devices..." -msgstr "Dispositivos &MCA..." +msgid "&MCA devices…" +msgstr "Dispositivos &MCA…" msgid "Show non-&primary monitors" msgstr "Mostrar monitores não &primários" -msgid "Open screenshots &folder..." -msgstr "Ab&rir pasta de capturas de tela..." +msgid "Open screenshots &folder…" +msgstr "Ab&rir pasta de capturas de tela…" msgid "Appl&y fullscreen stretch mode when maximized" msgstr "Apl&icar modo de ampliação em tela cheia quando maximizado" @@ -1707,8 +1668,8 @@ msgstr "&Conectado" msgid "Clear image &history" msgstr "Limpar &histórico de imagens" -msgid "Create..." -msgstr "Criar..." +msgid "Create…" +msgstr "Criar…" msgid "Host CD/DVD Drive (%1)" msgstr "Unidade de CD/DVD do anfitrião (%1)" @@ -1749,8 +1710,8 @@ msgstr "Shaders" msgid "Remove" msgstr "Remover" -msgid "Browse..." -msgstr "Procurar..." +msgid "Browse…" +msgstr "Procurar…" msgid "Couldn't create OpenGL context." msgstr "Não foi possível criar o contexto OpenGL." @@ -1765,7 +1726,7 @@ msgid "Error initializing OpenGL" msgstr "Erro ao inicializar o OpenGL" msgid "\nFalling back to software rendering." -msgstr "\nVoltando à renderização de software." +msgstr "\nRevertendo para renderização via software." msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" msgstr "

Ao selecionar imagens de mídia (CD-ROM, disquete, etc.), a caixa de diálogo de abertura será iniciada no mesmo diretório do arquivo de configuração do 86Box. Essa configuração provavelmente só fará diferença no macOS.

" @@ -1839,8 +1800,8 @@ msgstr "Passagem de porta serial 3" msgid "Serial port passthrough 4" msgstr "Passagem de porta serial 4" -msgid "Renderer &options..." -msgstr "&Opções do renderizador..." +msgid "Renderer &options…" +msgstr "&Opções do renderizador…" msgid "PC/XT Keyboard" msgstr "Teclado PC/XT" @@ -1893,8 +1854,8 @@ msgstr "3M MicroTouch (serial)" msgid "Default Baud rate" msgstr "Taxa de transmissão padrão" -msgid "[COM] Standard Hayes-compliant Modem" -msgstr "[COM] Modem padrão compatível com Hayes" +msgid "Standard Hayes-compliant Modem" +msgstr "Modem padrão compatível com Hayes" msgid "Roland MT-32 Emulation" msgstr "Emulação do Roland MT-32" @@ -1977,6 +1938,9 @@ msgstr "IRQ da porta serial" msgid "Parallel port IRQ" msgstr "IRQ da porta paralela" +msgid "Hard disk" +msgstr "Disco rígido" + msgid "BIOS Revision" msgstr "Revisão do BIOS" @@ -2052,9 +2016,6 @@ msgstr "Passagem da entrada MIDI" msgid "MIDI Clockout" msgstr "Saída do relógio MIDI" -msgid "SoundFont" -msgstr "SoundFont" - msgid "Output Gain" msgstr "Ganho de saída" @@ -2847,9 +2808,6 @@ msgstr "Alternar tela cheia" msgid "Toggle UI in fullscreen" msgstr "Alternar interface em tela cheia" -msgid "Screenshot" -msgstr "Captura de tela" - msgid "Release mouse pointer" msgstr "Liberar ponteiro do mouse" @@ -2908,7 +2866,7 @@ msgid "%1 VM Manager" msgstr "Gerenciador de MV do %1" msgid "%n disk(s)" -msgstr "%1 disco(s)" +msgstr "%n disco(s)" msgid "Unknown Status" msgstr "Estado desconhecido" @@ -2964,8 +2922,8 @@ msgstr "Visitar página de download" msgid "Update check" msgstr "Verificação de atualização" -msgid "Checking for updates..." -msgstr "Verificando por atualizações..." +msgid "Checking for updates…" +msgstr "Verificando por atualizações…" msgid "86Box Update" msgstr "Atualização do 86Box" @@ -3003,8 +2961,8 @@ msgstr "Brilho" msgid "Sharpness" msgstr "Nitidez" -msgid "&CGA composite settings..." -msgstr "Configurações do modo composto &CGA..." +msgid "&CGA composite settings…" +msgstr "Configurações do modo composto &CGA…" msgid "CGA composite settings" msgstr "Configurações do modo composto CGA" @@ -3012,8 +2970,8 @@ msgstr "Configurações do modo composto CGA" msgid "Monitor EDID" msgstr "EDID do monitor" -msgid "Export..." -msgstr "Exportar..." +msgid "Export…" +msgstr "Exportar…" msgid "Export EDID" msgstr "Exportar EDID" @@ -3038,3 +2996,24 @@ msgstr "Escuro" msgid "Search:" msgstr "Pesquisar:" + +msgid "Force interpretation" +msgstr "Forçar interpretação" + +msgid "Allow recompilation" +msgstr "Permitir recompilação" + +msgid "&Force interpretation" +msgstr "&Forçar interpretação" + +msgid "&Allow recompilation" +msgstr "&Permitir recompilação" + +msgid "&Fast forward" +msgstr "" + +msgid "Fast forward" +msgstr "" + +msgid "To change the system directory, stop all running machines." +msgstr "" diff --git a/src/qt/languages/pt-PT.po b/src/qt/languages/pt-PT.po index 177ef25f62f..f18eb8f1ab8 100644 --- a/src/qt/languages/pt-PT.po +++ b/src/qt/languages/pt-PT.po @@ -73,8 +73,8 @@ msgstr "Open&GL (Núcleo 3.0)" msgid "&VNC" msgstr "&VNC" -msgid "Specify &dimensions..." -msgstr "&Especificar dimensões..." +msgid "Specify &dimensions…" +msgstr "&Especificar dimensões…" msgid "Force &4:3 display ratio" msgstr "Forçar rácio de visualização &4:3" @@ -199,11 +199,11 @@ msgstr "&Media" msgid "&Tools" msgstr "&Ferramentas" -msgid "&Settings..." -msgstr "&Definições..." +msgid "&Settings…" +msgstr "&Definições…" -msgid "Settings..." -msgstr "Definições..." +msgid "Settings…" +msgstr "Definições…" msgid "&Update status bar icons" msgstr "&Atualizar ícones da barra de estado" @@ -211,17 +211,38 @@ msgstr "&Atualizar ícones da barra de estado" msgid "Take s&creenshot" msgstr "Gravar imagem de &ecrã" +msgid "Take screenshot" +msgstr "Gravar imagem de ecrã" + +msgid "Take &raw screenshot" +msgstr "Gravar imagem &bruta de ecrã" + +msgid "Take raw screenshot" +msgstr "Gravar imagem bruta de ecrã" + +msgid "C&opy screenshot" +msgstr "&Copiar imagem de ecrã" + +msgid "Copy screenshot" +msgstr "Copiar imagem de ecrã" + +msgid "Copy r&aw screenshot" +msgstr "Copiar imagem b&ruta de ecrã" + +msgid "Copy raw screenshot" +msgstr "Copiar imagem bruta de ecrã" + msgid "S&ound" msgstr "&Som" -msgid "&Preferences..." -msgstr "&Preferências..." +msgid "&Preferences…" +msgstr "&Preferências…" msgid "Enable &Discord integration" msgstr "Ativar integração com D&iscord" -msgid "Sound &gain..." -msgstr "&Ganho de som..." +msgid "Sound &gain…" +msgstr "&Ganho de som…" msgid "Begin trace" msgstr "Iniciar o rastreio" @@ -232,20 +253,20 @@ msgstr "Terminar o rastreio" msgid "&Help" msgstr "Aj&uda" -msgid "&Documentation..." -msgstr "&Documentação..." +msgid "&Documentation…" +msgstr "&Documentação…" -msgid "&About 86Box..." -msgstr "&Acerca do 86Box..." +msgid "&About 86Box…" +msgstr "&Acerca do 86Box…" -msgid "&New image..." -msgstr "&Nova imagem..." +msgid "&New image…" +msgstr "&Nova imagem…" -msgid "&Existing image..." -msgstr "Imagem &existente..." +msgid "&Existing image…" +msgstr "Imagem &existente…" -msgid "Existing image (&Write-protected)..." -msgstr "Imagem existente (&Proteção contra escrita)..." +msgid "Existing image (&Write-protected)…" +msgstr "Imagem existente (&Proteção contra escrita)…" msgid "&Record" msgstr "&Gravar" @@ -262,11 +283,11 @@ msgstr "&Avanço rápido para o fim" msgid "E&ject" msgstr "E&jetar" -msgid "&Image..." -msgstr "&Imagem..." +msgid "&Image…" +msgstr "&Imagem…" -msgid "E&xport to 86F..." -msgstr "E&xportar para 86F..." +msgid "E&xport to 86F…" +msgstr "E&xportar para 86F…" msgid "&Mute" msgstr "&Desativar som" @@ -277,8 +298,8 @@ msgstr "&CDROM vazio" msgid "Reload previous image" msgstr "Recarregar imagem anterior" -msgid "&Folder..." -msgstr "&Pasta..." +msgid "&Folder…" +msgstr "&Pasta…" msgid "Preferences" msgstr "Preferências" @@ -424,17 +445,17 @@ msgstr "Joystick:" msgid "Joystick" msgstr "Joystick" -msgid "Joystick 1..." -msgstr "Joystick 1..." +msgid "Joystick 1…" +msgstr "Joystick 1…" -msgid "Joystick 2..." -msgstr "Joystick 2..." +msgid "Joystick 2…" +msgstr "Joystick 2…" -msgid "Joystick 3..." -msgstr "Joystick 3..." +msgid "Joystick 3…" +msgstr "Joystick 3…" -msgid "Joystick 4..." -msgstr "Joystick 4..." +msgid "Joystick 4…" +msgstr "Joystick 4…" msgid "Sound card #1:" msgstr "Placa de som 1:" @@ -523,10 +544,10 @@ msgstr "Porta paralela 3" msgid "Parallel port 4" msgstr "Porta paralela 4" -msgid "FD Controller:" -msgstr "Controlador FD:" +msgid "Floppy disk controller:" +msgstr "Controlador de disquetes:" -msgid "CD-ROM Controller:" +msgid "CD-ROM controller:" msgstr "Controlador CD-ROM:" msgid "Tertiary IDE Controller" @@ -535,11 +556,11 @@ msgstr "Controlador IDE terciário" msgid "Quaternary IDE Controller" msgstr "Controlador IDE quaternário" -msgid "Hard disk" -msgstr "Disco rígido" +msgid "Hard disk controllers" +msgstr "Controladores de disco rígido" -msgid "SCSI" -msgstr "SCSI" +msgid "SCSI controllers" +msgstr "Controladores SCSI" msgid "Controller 1:" msgstr "Controlador 1:" @@ -562,11 +583,11 @@ msgstr "Discos rígidos:" msgid "Firmware Version" msgstr "Versão de firmware" -msgid "&New..." -msgstr "&Novo..." +msgid "&New…" +msgstr "&Novo…" -msgid "&Existing..." -msgstr "&Existente..." +msgid "&Existing…" +msgstr "&Existente…" msgid "&Remove" msgstr "&Remover" @@ -874,9 +895,6 @@ msgstr "Manípulo(s) de jogos de 4 botões" msgid "6-button gamepad" msgstr "Manípulo(s) de jogos de 6 botões" -msgid "Gravis PC GamePad" -msgstr "GamePad Gravis PC" - msgid "2-button flight yoke" msgstr "Manípulo de voo de 2 botões" @@ -904,51 +922,6 @@ msgstr "Volante (de 3 eixos, 3 botões)" msgid "Steering wheel (3-axis, 4-button)" msgstr "Volante (de 3 eixos, 4 botões)" -msgid "CH Flightstick" -msgstr "CH Flightstick" - -msgid "CH Flightstick + CH Pedals" -msgstr "CH Flightstick + CH Pedals" - -msgid "CH Flightstick + CH Pedals Pro" -msgstr "CH Flightstick + CH Pedals Pro" - -msgid "CH Flightstick Pro" -msgstr "CH Flightstick Pro" - -msgid "CH Flightstick Pro + CH Pedals" -msgstr "CH Flightstick Pro + Pedais CH" - -msgid "CH Flightstick Pro + CH Pedals Pro" -msgstr "CH Flightstick Pro + Pedais CH Pro" - -msgid "CH Virtual Pilot" -msgstr "CH Virtual Pilot" - -msgid "CH Virtual Pilot + CH Pedals" -msgstr "CH Virtual Pilot + Pedais CH" - -msgid "CH Virtual Pilot + CH Pedals Pro" -msgstr "CH Virtual Pilot + Pedais CH Pro" - -msgid "CH Virtual Pilot Pro" -msgstr "CH Virtual Pilot Pro" - -msgid "CH Virtual Pilot Pro + CH Pedals" -msgstr "CH Virtual Pilot Pro + Pedais CH" - -msgid "CH Virtual Pilot Pro + CH Pedals Pro" -msgstr "CH Virtual Pilot Pro + Pedais CH Pro" - -msgid "Microsoft SideWinder Pad" -msgstr "Microsoft SideWinder Pad" - -msgid "Thrustmaster Flight Control System" -msgstr "Sistema de controlo de voo Thrustmaster" - -msgid "Thrustmaster FCS + Rudder Control System" -msgstr "SCV Thrustmaster + Sistema de controlo do leme" - msgid "Thrustmaster Formula T1/T2 with adapter" msgstr "Thrustmaster Formula T1/T2 com adaptador" @@ -1003,11 +976,17 @@ msgstr "Dispositivo integrado" msgid "&File" msgstr "F&icheiro" -msgid "&New machine..." -msgstr "&Nova máquina..." +msgid "&New machine…" +msgstr "&Nova máquina…" + +msgid "New machine…" +msgstr "Nova máquina…" + +msgid "New machine" +msgstr "Nova máquina" -msgid "&Check for updates..." -msgstr "&Verificar para atualizações..." +msgid "&Check for updates…" +msgstr "&Verificar para atualizações…" msgid "Exit" msgstr "Sair" @@ -1177,8 +1156,8 @@ msgstr "Não foi possível abrir o ficheir de configurção seleccionado para le msgid "Use regular expressions in search box" msgstr "Usa expressões regulares na caixa de procura" -msgid "%1 machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" -msgstr "%1 máquina(s) estão actualmente activas. Quer mesmo sair do gerenciador de MVs?" +msgid "%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" +msgstr "%n máquina(s) estão actualmente activas. Quer mesmo sair do gerenciador de MVs?" msgid "Add new system wizard" msgstr "Assistende de adicionamento do novo sistema" @@ -1258,26 +1237,23 @@ msgstr "Definir o nome apresentado" msgid "Enter the new display name (blank to reset)" msgstr "Escreve o nome apresentado (vazio para repor)" -msgid "Change &display name..." -msgstr "Alterar o nome &apresentado..." +msgid "Change &display name…" +msgstr "Alterar o nome &apresentado…" -msgid "Context Menu" -msgstr "Menu de contexto" +msgid "&Open folder…" +msgstr "&Abrir pasta…" -msgid "&Open folder..." -msgstr "&Abrir pasta..." +msgid "Open p&rinter tray…" +msgstr "Abrir &bandeja de impressora…" -msgid "Open p&rinter tray..." -msgstr "Abrir &bandeja de impressora..." - -msgid "Set &icon..." -msgstr "Definir &ícone..." +msgid "Set &icon…" +msgstr "Definir &ícone…" msgid "Select an icon" msgstr "Seleccionar um ícone" -msgid "C&lone..." -msgstr "C&lonar..." +msgid "C&lone…" +msgstr "C&lonar…" msgid "Virtual machine \"%1\" (%2) will be cloned into:" msgstr "A máquina virtual \"%1\" (%2) será clonada para:" @@ -1363,8 +1339,8 @@ msgstr "Sem capturas de ecrã" msgid "Search" msgstr "Procurar" -msgid "Searching for VMs..." -msgstr "A procurar para MVs..." +msgid "Searching for VMs…" +msgstr "A procurar para MVs…" msgid "Found %1" msgstr "%1 encontrado" @@ -1399,11 +1375,11 @@ msgstr "Disco rígido (%1)" msgid "MFM/RLL or ESDI CD-ROM drives never existed" msgstr "Unidades CD-ROM com barramento MFM/RLL ou ESDI nunca existiram" -msgid "Custom..." -msgstr "Personalizado..." +msgid "Custom…" +msgstr "Personalizado…" -msgid "Custom (large)..." -msgstr "Personalizado (grande)..." +msgid "Custom (large)…" +msgstr "Personalizado (grande)…" msgid "Add New Hard Disk" msgstr "Adicionar novo disco rígido" @@ -1522,21 +1498,6 @@ msgstr "Os carimbos de data/hora dos discos pai e filho não correspondem" msgid "Could not fix VHD timestamp." msgstr "Não foi possível corrigir o carimbo de data/hora do VHD." -msgid "MFM/RLL" -msgstr "MFM/RLL" - -msgid "XTA" -msgstr "XTA" - -msgid "ESDI" -msgstr "ESDI" - -msgid "IDE" -msgstr "IDE" - -msgid "ATAPI" -msgstr "ATAPI" - msgid "CD-ROM %1 (%2): %3" msgstr "CD-ROM %1 (%2): %3" @@ -1687,14 +1648,14 @@ msgstr "Ferramenta para tablet" msgid "About &Qt" msgstr "Acerca do &Qt" -msgid "&MCA devices..." -msgstr "Dispositivos MCA..." +msgid "&MCA devices…" +msgstr "Dispositivos MCA…" msgid "Show non-&primary monitors" msgstr "Mostrar monitores não &primários" -msgid "Open screenshots &folder..." -msgstr "Abrir a pas&ta de capturas de ecrã..." +msgid "Open screenshots &folder…" +msgstr "Abrir a pas&ta de capturas de ecrã…" msgid "Appl&y fullscreen stretch mode when maximized" msgstr "Apl&icar o modo de estiramento na tela cheia quando maximizado" @@ -1714,8 +1675,8 @@ msgstr "&Conectado" msgid "Clear image &history" msgstr "Limpar o histórico de imagens(&H)" -msgid "Create..." -msgstr "Criar..." +msgid "Create…" +msgstr "Criar…" msgid "Host CD/DVD Drive (%1)" msgstr "Unidade de CD/DVD do anfitrião (%1)" @@ -1756,8 +1717,8 @@ msgstr "Shaders" msgid "Remove" msgstr "Remover" -msgid "Browse..." -msgstr "Navegar..." +msgid "Browse…" +msgstr "Navegar…" msgid "Couldn't create OpenGL context." msgstr "Não foi possível criar o contexto OpenGL." @@ -1846,8 +1807,8 @@ msgstr "Passagem da porta de série 3" msgid "Serial port passthrough 4" msgstr "Passagem da porta de série 4" -msgid "Renderer &options..." -msgstr "Opções do re&nderizador..." +msgid "Renderer &options…" +msgstr "Opções do re&nderizador…" msgid "PC/XT Keyboard" msgstr "Teclado PC/XT" @@ -1900,8 +1861,8 @@ msgstr "3M MicroTouch (série)" msgid "Default Baud rate" msgstr "Velocidade de transmissão padrão" -msgid "[COM] Standard Hayes-compliant Modem" -msgstr "[COM] Modem padrão compatível com Hayes" +msgid "Standard Hayes-compliant Modem" +msgstr "Modem padrão compatível com Hayes" msgid "Roland MT-32 Emulation" msgstr "Emulação do Roland MT-32" @@ -1984,6 +1945,9 @@ msgstr "IRQ da porta série" msgid "Parallel port IRQ" msgstr "IRQ da porta paralela" +msgid "Hard disk" +msgstr "Disco rígido" + msgid "BIOS Revision" msgstr "Revisão da BIOS" @@ -2059,9 +2023,6 @@ msgstr "Passagem da entrada MIDI" msgid "MIDI Clockout" msgstr "Saída do relógio MIDI" -msgid "SoundFont" -msgstr "Fonte de som" - msgid "Output Gain" msgstr "Ganho de saída" @@ -2854,9 +2815,6 @@ msgstr "Alternar o modo em ecrã cheio" msgid "Toggle UI in fullscreen" msgstr "Alternar interface do utilizador em ecrã inteiro" -msgid "Screenshot" -msgstr "Captura de ecrã" - msgid "Release mouse pointer" msgstr "Soltar o ponteiro do rato" @@ -2971,8 +2929,8 @@ msgstr "Visitar a pagina de transferências" msgid "Update check" msgstr "Verificar atualizações" -msgid "Checking for updates..." -msgstr "A verificar para atualizações..." +msgid "Checking for updates…" +msgstr "A verificar para atualizações…" msgid "86Box Update" msgstr "Atualização do 86Box" @@ -3010,8 +2968,8 @@ msgstr "Brilho" msgid "Sharpness" msgstr "Nitidez" -msgid "&CGA composite settings..." -msgstr "Definições do modo compósito &CGA..." +msgid "&CGA composite settings…" +msgstr "Definições do modo compósito &CGA…" msgid "CGA composite settings" msgstr "Definições do modo compósito CGA" @@ -3019,8 +2977,8 @@ msgstr "Definições do modo compósito CGA" msgid "Monitor EDID" msgstr "EDID do monitor" -msgid "Export..." -msgstr "Exportar..." +msgid "Export…" +msgstr "Exportar…" msgid "Export EDID" msgstr "Exportar EDID" @@ -3045,3 +3003,24 @@ msgstr "Escuro" msgid "Search:" msgstr "Procurar:" + +msgid "Force interpretation" +msgstr "Forçar interpretação" + +msgid "Allow recompilation" +msgstr "Permitir recompilação" + +msgid "&Force interpretation" +msgstr "&Forçar interpretação" + +msgid "&Allow recompilation" +msgstr "&Permitir recompilação" + +msgid "&Fast forward" +msgstr "" + +msgid "Fast forward" +msgstr "" + +msgid "To change the system directory, stop all running machines." +msgstr "" diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index 0b20956e747..6102dceeda4 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -1,8 +1,15 @@ msgid "" msgstr "" +"PO-Revision-Date: 2026-01-10 12:56+0000\n" +"Last-Translator: Alexander Babikov \n" +"Language-Team: Russian \n" +"Language: ru-RU\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Weblate 5.12.2\n" "X-Language: ru_RU\n" "X-Source-Language: en_US\n" @@ -13,7 +20,7 @@ msgid "&Keyboard requires capture" msgstr "&Клавиатура требует захвата" msgid "&Right CTRL is left ALT" -msgstr "&Правый CTRL - это левый ALT" +msgstr "П&равый CTRL - это левый ALT" msgid "&Hard reset" msgstr "&Холодная перезагрузка" @@ -66,8 +73,8 @@ msgstr "Open&GL (3.0 Core)" msgid "&VNC" msgstr "&VNC" -msgid "Specify &dimensions..." -msgstr "&Указать размеры главного окна..." +msgid "Specify &dimensions…" +msgstr "&Указать размеры главного окна…" msgid "Force &4:3 display ratio" msgstr "Установить соотношение сторон &4:3" @@ -136,7 +143,7 @@ msgid "&Integer scale" msgstr "&Целочисленное масштабирование" msgid "4:&3 Integer scale" -msgstr "4:&3 Целочисленное масштабирование" +msgstr "4:&3 целочисленное масштабирование" msgid "EGA/(S)&VGA settings" msgstr "Настройки EGA/(S)&VGA" @@ -192,11 +199,11 @@ msgstr "&Носители" msgid "&Tools" msgstr "&Инструменты" -msgid "&Settings..." -msgstr "&Настройки машины..." +msgid "&Settings…" +msgstr "&Настройки машины…" -msgid "Settings..." -msgstr "Настройки машины..." +msgid "Settings…" +msgstr "Настройки машины…" msgid "&Update status bar icons" msgstr "&Обновление значков строки состояния" @@ -204,17 +211,38 @@ msgstr "&Обновление значков строки состояния" msgid "Take s&creenshot" msgstr "Сделать с&криншот" +msgid "Take screenshot" +msgstr "Сделать скриншот" + +msgid "Take &raw screenshot" +msgstr "Сделать н&еобработанный скриншот" + +msgid "Take raw screenshot" +msgstr "Сделать необработанный скриншот" + +msgid "C&opy screenshot" +msgstr "Ско&пировать скриншот" + +msgid "Copy screenshot" +msgstr "Скопировать скриншот" + +msgid "Copy r&aw screenshot" +msgstr "Скопировать необработанный скрин&шот" + +msgid "Copy raw screenshot" +msgstr "Скопировать необработанный скриншот" + msgid "S&ound" msgstr "&Звук" -msgid "&Preferences..." -msgstr "&Параметры..." +msgid "&Preferences…" +msgstr "&Параметры…" msgid "Enable &Discord integration" -msgstr "Включить интеграцию &Discord" +msgstr "Включить интеграцию с &Discord" -msgid "Sound &gain..." -msgstr "&Усиление звука..." +msgid "Sound &gain…" +msgstr "&Усиление звука…" msgid "Begin trace" msgstr "Начать трассировку" @@ -225,20 +253,20 @@ msgstr "Завершить трассировку" msgid "&Help" msgstr "&Справка" -msgid "&Documentation..." -msgstr "&Документация..." +msgid "&Documentation…" +msgstr "&Документация…" -msgid "&About 86Box..." -msgstr "&О 86Box..." +msgid "&About 86Box…" +msgstr "&О 86Box…" -msgid "&New image..." -msgstr "&Новый образ..." +msgid "&New image…" +msgstr "&Новый образ…" -msgid "&Existing image..." -msgstr "&Выбрать образ..." +msgid "&Existing image…" +msgstr "&Выбрать образ…" -msgid "Existing image (&Write-protected)..." -msgstr "Выбрать образ (&Защита от записи)..." +msgid "Existing image (&Write-protected)…" +msgstr "Выбрать образ (с &защитой от записи)…" msgid "&Record" msgstr "&Запись" @@ -255,11 +283,11 @@ msgstr "&Перемотка в конец" msgid "E&ject" msgstr "И&звлечь" -msgid "&Image..." -msgstr "&Образ..." +msgid "&Image…" +msgstr "&Образ…" -msgid "E&xport to 86F..." -msgstr "Э&кспорт в 86F..." +msgid "E&xport to 86F…" +msgstr "Э&кспорт в 86F…" msgid "&Mute" msgstr "О&тключить звук" @@ -270,8 +298,8 @@ msgstr "П&устой" msgid "Reload previous image" msgstr "Перезагрузить предыдущий образ" -msgid "&Folder..." -msgstr "&Папка..." +msgid "&Folder…" +msgstr "&Папка…" msgid "Preferences" msgstr "Параметры" @@ -417,17 +445,17 @@ msgstr "Джойстик:" msgid "Joystick" msgstr "Джойстик" -msgid "Joystick 1..." -msgstr "Джойстик 1..." +msgid "Joystick 1…" +msgstr "Джойстик 1…" -msgid "Joystick 2..." -msgstr "Джойстик 2..." +msgid "Joystick 2…" +msgstr "Джойстик 2…" -msgid "Joystick 3..." -msgstr "Джойстик 3..." +msgid "Joystick 3…" +msgstr "Джойстик 3…" -msgid "Joystick 4..." -msgstr "Джойстик 4..." +msgid "Joystick 4…" +msgstr "Джойстик 4…" msgid "Sound card #1:" msgstr "Звуковая карта № 1:" @@ -516,23 +544,23 @@ msgstr "Параллельный порт LPT3" msgid "Parallel port 4" msgstr "Параллельный порт LPT4" -msgid "FD Controller:" -msgstr "Контроллер FD:" +msgid "Floppy disk controller:" +msgstr "Контроллер гибких дисков:" -msgid "CD-ROM Controller:" +msgid "CD-ROM controller:" msgstr "Контроллер CD-ROM:" msgid "Tertiary IDE Controller" -msgstr "Третичный IDE контроллер" +msgstr "Третичный контроллер IDE" msgid "Quaternary IDE Controller" -msgstr "Четвертичный IDE контроллер" +msgstr "Четвертичный контроллер IDE" -msgid "Hard disk" -msgstr "Жёсткий диск" +msgid "Hard disk controllers" +msgstr "Контроллеры жёстких дисков" -msgid "SCSI" -msgstr "SCSI" +msgid "SCSI controllers" +msgstr "Контроллеры SCSI" msgid "Controller 1:" msgstr "Контроллер 1:" @@ -547,7 +575,7 @@ msgid "Controller 4:" msgstr "Контроллер 4:" msgid "Cassette" -msgstr "Кассета" +msgstr "Кассетный магнитофон" msgid "Hard disks:" msgstr "Жёсткие диски:" @@ -555,11 +583,11 @@ msgstr "Жёсткие диски:" msgid "Firmware Version" msgstr "Версия прошивки" -msgid "&New..." -msgstr "&Создать..." +msgid "&New…" +msgstr "&Создать…" -msgid "&Existing..." -msgstr "&Выбрать..." +msgid "&Existing…" +msgstr "&Выбрать…" msgid "&Remove" msgstr "&Удалить" @@ -706,7 +734,7 @@ msgid "Basic sector images" msgstr "Простые посекторные образы" msgid "Surface images" -msgstr "Surface образы" +msgstr "Образы поверхности" msgid "Machine \"%hs\" is not available due to missing ROMs in the roms/machines directory. Switching to an available machine." msgstr "Системная плата «%hs» недоступна из-за отсутствия файла её ПЗУ в каталоге roms/machines. Переключение на доступную системную плату." @@ -867,9 +895,6 @@ msgstr "4-кнопочный геймпад" msgid "6-button gamepad" msgstr "6-кнопочный геймпад" -msgid "Gravis PC GamePad" -msgstr "Gravis PC GamePad" - msgid "2-button flight yoke" msgstr "2-кнопочный штурвал" @@ -897,51 +922,6 @@ msgstr "Руль (3-осевой, 3-кнопочный)" msgid "Steering wheel (3-axis, 4-button)" msgstr "Руль (3-осевой, 4-кнопочный)" -msgid "CH Flightstick" -msgstr "CH Flightstick" - -msgid "CH Flightstick + CH Pedals" -msgstr "CH Flightstick + CH Педали" - -msgid "CH Flightstick + CH Pedals Pro" -msgstr "CH Flightstick + CH Педали Pro" - -msgid "CH Flightstick Pro" -msgstr "CH Flightstick Pro" - -msgid "CH Flightstick Pro + CH Pedals" -msgstr "CH Flightstick Pro + CH Педали" - -msgid "CH Flightstick Pro + CH Pedals Pro" -msgstr "CH Flightstick Pro + CH Педали Pro" - -msgid "CH Virtual Pilot" -msgstr "CH Virtual Pilot" - -msgid "CH Virtual Pilot + CH Pedals" -msgstr "CH Virtual Pilot + CH Педали" - -msgid "CH Virtual Pilot + CH Pedals Pro" -msgstr "CH Virtual Pilot + CH Педали Pro" - -msgid "CH Virtual Pilot Pro" -msgstr "CH Virtual Pilot Pro" - -msgid "CH Virtual Pilot Pro + CH Pedals" -msgstr "CH Virtual Pilot Pro + CH Педали" - -msgid "CH Virtual Pilot Pro + CH Pedals Pro" -msgstr "CH Virtual Pilot Pro + CH Педали Pro" - -msgid "Microsoft SideWinder Pad" -msgstr "Microsoft SideWinder Pad" - -msgid "Thrustmaster Flight Control System" -msgstr "Система управления полётом Thrustmaster" - -msgid "Thrustmaster FCS + Rudder Control System" -msgstr "Thrustmaster FCS + Система управления рулём" - msgid "Thrustmaster Formula T1/T2 with adapter" msgstr "Thrustmaster Formula T1/T2 с адаптером" @@ -996,11 +976,17 @@ msgstr "Встроенное устройство" msgid "&File" msgstr "&Файл" -msgid "&New machine..." -msgstr "&Новая машина..." +msgid "&New machine…" +msgstr "&Новая машина…" + +msgid "New machine…" +msgstr "Новая машина…" -msgid "&Check for updates..." -msgstr "&Проверить обновления..." +msgid "New machine" +msgstr "Новая машина" + +msgid "&Check for updates…" +msgstr "&Проверить обновления…" msgid "Exit" msgstr "Выход" @@ -1009,7 +995,7 @@ msgid "No ROMs found" msgstr "ПЗУ не найдены" msgid "Do you want to save the settings?" -msgstr "Хотите ли вы сохранить настройки?" +msgstr "Вы хотите сохранить настройки?" msgid "This will hard reset the emulated machine." msgstr "Это приведёт к холодной перезагрузке эмулируемой машины." @@ -1021,7 +1007,19 @@ msgid "About %1" msgstr "О %1" msgid "An emulator of old computers\n\nAuthors: Miran Grča (OBattler), RichardG867, Jasmine Iwanek, TC1995, coldbrewed, Teemu Korhonen (Manaatti), Joakim L. Gilje, Adrien Moulin (elyosh), Daniel Balsom (gloriouscow), Cacodemon345, Fred N. van Kempen (waltje), Tiseno100, reenigne, and others.\n\nWith previous core contributions from Sarah Walker, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." -msgstr "Эмулятор старых компьютеров\n\nАвторы: Miran Grča (OBattler), RichardG867, Jasmine Iwanek, TC1995, coldbrewed, Teemu Korhonen (Manaatti), Joakim L. Gilje, Adrien Moulin (elyosh), Daniel Balsom (gloriouscow), Cacodemon345, Fred N. van Kempen (waltje), Tiseno100, reenigne, and others.\n\nС предыдущими основными материалами от Sarah Walker, leilei, JohnElliott, greatpsycho и других.\n\nВыпускается под лицензией GNU General Public License версии 2 или более поздней. Дополнительную информацию см. в файле LICENSE." +msgstr "" +"Эмулятор старых компьютеров\n" +"\n" +"Авторы: Miran Grča (OBattler), RichardG867, Jasmine Iwanek, TC1995, " +"coldbrewed, Teemu Korhonen (Manaatti), Joakim L. Gilje, Adrien Moulin " +"(elyosh), Daniel Balsom (gloriouscow), Cacodemon345, Fred N. van Kempen " +"(waltje), Tiseno100, reenigne, и другие.\n" +"\n" +"С предыдущими основными материалами от Sarah Walker, leilei, JohnElliott, " +"greatpsycho и других.\n" +"\n" +"Выпускается под лицензией GNU General Public License версии 2 или более " +"поздней. Дополнительную информацию см. в файле LICENSE." msgid "Hardware not available" msgstr "Оборудование недоступно" @@ -1170,8 +1168,8 @@ msgstr "Невозможно открыть выбранный файл конф msgid "Use regular expressions in search box" msgstr "Использовать регулярные выражения в поле поиска" -msgid "%1 machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" -msgstr "%1 машина(ы) в настоящее время активна(ы). Вы уверены, что всё равно хотите выйти из менеджера виртуальной машины?" +msgid "%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" +msgstr "%n машина(ы) в настоящее время активна(ы). Вы уверены, что всё равно хотите выйти из менеджера виртуальной машины?" msgid "Add new system wizard" msgstr "Мастер добавления новой системы" @@ -1195,7 +1193,7 @@ msgid "Use existing configuration" msgstr "Использовать существующую конфигурацию" msgid "Type some notes here" -msgstr "Введите здесь несколько заметок" +msgstr "Введите заметки" msgid "Paste the contents of the existing configuration file into the box below." msgstr "Вставьте содержимое существующего файла конфигурации в поле ниже." @@ -1222,16 +1220,16 @@ msgid "Directory does not exist" msgstr "Папка не существует" msgid "A new directory for the system will be created in the selected directory above" -msgstr "Новая папка для системы будет создана в выбранной папке выше" +msgstr "Новая папка для системы будет создана в указанной выше папке" msgid "System location:" msgstr "Расположение системы:" msgid "System name and location" -msgstr "Название системы и расположение" +msgstr "Название системы и её расположение" msgid "Enter the name of the system and choose the location" -msgstr "Введите название системы и выберите расположение" +msgstr "Введите название системы и выберите её расположение" msgid "Enter the name of the system" msgstr "Введите название системы" @@ -1249,28 +1247,25 @@ msgid "Set display name" msgstr "Установить отображаемое имя" msgid "Enter the new display name (blank to reset)" -msgstr "Введите новое отображаемое имя (пусто, чтобы сбросить)" - -msgid "Change &display name..." -msgstr "Изменить &отображаемое имя..." +msgstr "Введите новое отображаемое имя (оставьте поле пустым, чтобы сбросить)" -msgid "Context Menu" -msgstr "Контекстное меню" +msgid "Change &display name…" +msgstr "Изменить &отображаемое имя…" -msgid "&Open folder..." -msgstr "&Открыть папку..." +msgid "&Open folder…" +msgstr "&Открыть папку…" -msgid "Open p&rinter tray..." -msgstr "Открыть папку &принтера..." +msgid "Open p&rinter tray…" +msgstr "Открыть папку &принтера…" -msgid "Set &icon..." -msgstr "Установить &значок..." +msgid "Set &icon…" +msgstr "Установить &значок…" msgid "Select an icon" msgstr "Выберите значок" -msgid "C&lone..." -msgstr "К&лонировать..." +msgid "C&lone…" +msgstr "К&лонировать…" msgid "Virtual machine \"%1\" (%2) will be cloned into:" msgstr "Виртуальная машина «%1» (%2) будет клонирована в:" @@ -1356,8 +1351,8 @@ msgstr "Нет скриншота" msgid "Search" msgstr "Поиск" -msgid "Searching for VMs..." -msgstr "Поиск виртуальных машин..." +msgid "Searching for VMs…" +msgstr "Поиск виртуальных машин…" msgid "Found %1" msgstr "Найдено %1" @@ -1392,11 +1387,11 @@ msgstr "Жёсткий диск (%1)" msgid "MFM/RLL or ESDI CD-ROM drives never existed" msgstr "MFM/RLL или ESDI дисководов CD-ROM никогда не существовало" -msgid "Custom..." -msgstr "Задать вручную..." +msgid "Custom…" +msgstr "Задать вручную…" -msgid "Custom (large)..." -msgstr "Задать вручную (large)..." +msgid "Custom (large)…" +msgstr "Задать вручную (большой размер)…" msgid "Add New Hard Disk" msgstr "Создать новый жёсткий диск" @@ -1456,7 +1451,7 @@ msgid "Don't overwrite" msgstr "Не перезаписывать" msgid "Raw image" -msgstr "RAW образ" +msgstr "Сырой образ" msgid "HDI image" msgstr "Образ HDI" @@ -1515,21 +1510,6 @@ msgstr "Временные метки родительского и дочерн msgid "Could not fix VHD timestamp." msgstr "Не удалось исправить временную метку VHD." -msgid "MFM/RLL" -msgstr "MFM/RLL" - -msgid "XTA" -msgstr "XTA" - -msgid "ESDI" -msgstr "ESDI" - -msgid "IDE" -msgstr "IDE" - -msgid "ATAPI" -msgstr "ATAPI" - msgid "CD-ROM %1 (%2): %3" msgstr "CD-ROM %1 (%2): %3" @@ -1630,7 +1610,7 @@ msgid "Mouse sensitivity:" msgstr "Чувствительность мыши:" msgid "Select media images from program working directory" -msgstr "Выбор медиа-образов из рабочего каталога программы" +msgstr "Выбор образов медиа из рабочего каталога программы" msgid "PIT mode:" msgstr "Режим PIT:" @@ -1680,14 +1660,14 @@ msgstr "Планшетный &инструмент" msgid "About &Qt" msgstr "О &Qt" -msgid "&MCA devices..." -msgstr "Устройства &MCA..." +msgid "&MCA devices…" +msgstr "Устройства &MCA…" msgid "Show non-&primary monitors" msgstr "&Показывать неосновные мониторы" -msgid "Open screenshots &folder..." -msgstr "Открыть папку &скриншотов..." +msgid "Open screenshots &folder…" +msgstr "Открыть папку &скриншотов…" msgid "Appl&y fullscreen stretch mode when maximized" msgstr "Применить полно&экранный режим растяжения при разворачивании окна" @@ -1699,7 +1679,7 @@ msgid "&Pen" msgstr "&Ручка" msgid "&Host CD/DVD Drive (%1:)" -msgstr "CD/DVD Привод &хоста (%1:)" +msgstr "CD/DVD привод &хоста (%1:)" msgid "&Connected" msgstr "&Кабель подключен" @@ -1707,11 +1687,11 @@ msgstr "&Кабель подключен" msgid "Clear image &history" msgstr "Очистить &историю образов" -msgid "Create..." -msgstr "Создать..." +msgid "Create…" +msgstr "Создать…" msgid "Host CD/DVD Drive (%1)" -msgstr "CD/DVD Привод хоста (%1)" +msgstr "CD/DVD привод хоста (%1)" msgid "Unknown Bus" msgstr "Неизвестная шина" @@ -1749,8 +1729,8 @@ msgstr "Шейдеры" msgid "Remove" msgstr "Удалить" -msgid "Browse..." -msgstr "Обзор..." +msgid "Browse…" +msgstr "Обзор…" msgid "Couldn't create OpenGL context." msgstr "Не удалось создать контекст OpenGL." @@ -1839,8 +1819,8 @@ msgstr "Сквозной последовательный порт COM3" msgid "Serial port passthrough 4" msgstr "Сквозной последовательный порт COM4" -msgid "Renderer &options..." -msgstr "Параметры &рендеринга..." +msgid "Renderer &options…" +msgstr "Параметры &рендеринга…" msgid "PC/XT Keyboard" msgstr "Клавиатура PC/XT" @@ -1893,8 +1873,8 @@ msgstr "3M MicroTouch (последовательный)" msgid "Default Baud rate" msgstr "Скорость передачи данных по умолчанию" -msgid "[COM] Standard Hayes-compliant Modem" -msgstr "[COM] Стандартный Hayes-совместимый модем" +msgid "Standard Hayes-compliant Modem" +msgstr "Стандартный Hayes-совместимый модем" msgid "Roland MT-32 Emulation" msgstr "Эмуляция Roland MT-32" @@ -1977,6 +1957,9 @@ msgstr "IRQ последовательного порта" msgid "Parallel port IRQ" msgstr "IRQ параллельного порта" +msgid "Hard disk" +msgstr "Жёсткий диск" + msgid "BIOS Revision" msgstr "Версия BIOS" @@ -2052,9 +2035,6 @@ msgstr "Пропускание MIDI-входа" msgid "MIDI Clockout" msgstr "MIDI Clockout" -msgid "SoundFont" -msgstr "SoundFont" - msgid "Output Gain" msgstr "Усиление выхода" @@ -2278,7 +2258,7 @@ msgid "Line doubling type" msgstr "Тип удвоения линии" msgid "Snow emulation" -msgstr "Эмуляция снега" +msgstr "Эмуляция «снега»" msgid "Monitor type" msgstr "Тип монитора" @@ -2611,7 +2591,7 @@ msgid "Color Non-Interlaced" msgstr "Цветной без чересстрочной развёртки" msgid "3Dfx Voodoo Graphics" -msgstr "Ускоритель 3Dfx Voodoo" +msgstr "3Dfx Voodoo Graphics" msgid "3Dfx Voodoo 2" msgstr "3Dfx Voodoo 2" @@ -2635,7 +2615,7 @@ msgid "Enabled" msgstr "Включено" msgid "Standard" -msgstr "Стандарт" +msgstr "Стандартный" msgid "High-Speed" msgstr "Высокоскоростной" @@ -2847,9 +2827,6 @@ msgstr "Переключить полноэкранный режим" msgid "Toggle UI in fullscreen" msgstr "Переключить UI в полноэкранном режиме" -msgid "Screenshot" -msgstr "Скриншот" - msgid "Release mouse pointer" msgstr "Отпустить указатель мыши" @@ -2964,8 +2941,8 @@ msgstr "Открыть страницу загрузки" msgid "Update check" msgstr "Проверка обновлений" -msgid "Checking for updates..." -msgstr "Проверка обновлений..." +msgid "Checking for updates…" +msgstr "Проверка обновлений…" msgid "86Box Update" msgstr "Обновление 86Box" @@ -3003,8 +2980,8 @@ msgstr "Яркость" msgid "Sharpness" msgstr "Резкость" -msgid "&CGA composite settings..." -msgstr "Настройки композитного видео &CGA..." +msgid "&CGA composite settings…" +msgstr "Настройки композитного видео &CGA…" msgid "CGA composite settings" msgstr "Настройки композитного видео CGA" @@ -3012,8 +2989,8 @@ msgstr "Настройки композитного видео CGA" msgid "Monitor EDID" msgstr "EDID монитора" -msgid "Export..." -msgstr "Экспорт..." +msgid "Export…" +msgstr "Экспорт…" msgid "Export EDID" msgstr "Экспорт EDID" @@ -3038,3 +3015,24 @@ msgstr "Тёмная" msgid "Search:" msgstr "Поиск:" + +msgid "Force interpretation" +msgstr "Принудительная интерпретация" + +msgid "Allow recompilation" +msgstr "Разрешить рекомпиляцию" + +msgid "&Force interpretation" +msgstr "Пр&инудительная интерпретация" + +msgid "&Allow recompilation" +msgstr "Разреш&ить рекомпиляцию" + +msgid "&Fast forward" +msgstr "П&еремотка вперёд" + +msgid "Fast forward" +msgstr "Перемотка вперёд" + +msgid "To change the system directory, stop all running machines." +msgstr "Чтобы изменить системную папку, остановите все запущенные машины." diff --git a/src/qt/languages/sk-SK.po b/src/qt/languages/sk-SK.po index 5f84e59fe84..a112005da81 100644 --- a/src/qt/languages/sk-SK.po +++ b/src/qt/languages/sk-SK.po @@ -72,8 +72,8 @@ msgstr "Open&GL (3.0 Core)" msgid "&VNC" msgstr "&VNC" -msgid "Specify &dimensions..." -msgstr "&Zadať veľkosť..." +msgid "Specify &dimensions…" +msgstr "&Zadať veľkosť…" msgid "Force &4:3 display ratio" msgstr "Zachovať pomer strán &4:3" @@ -198,11 +198,11 @@ msgstr "&Média" msgid "&Tools" msgstr "&Nástroje" -msgid "&Settings..." -msgstr "&Nastavenia..." +msgid "&Settings…" +msgstr "&Nastavenia…" -msgid "Settings..." -msgstr "Nastavenia..." +msgid "Settings…" +msgstr "Nastavenia…" msgid "&Update status bar icons" msgstr "&Aktualizovať ikony na stavovom riadku" @@ -210,17 +210,38 @@ msgstr "&Aktualizovať ikony na stavovom riadku" msgid "Take s&creenshot" msgstr "Urobiť snímku &obrazovky" +msgid "Take screenshot" +msgstr "Urobiť snímku obrazovky" + +msgid "Take &raw screenshot" +msgstr "Urobiť &surovú snímku obrazovky" + +msgid "Take raw screenshot" +msgstr "Urobiť surovú snímku obrazovky" + +msgid "C&opy screenshot" +msgstr "S&kopírovať snímku obrazovky" + +msgid "Copy screenshot" +msgstr "Skopírovať snímku obrazovky" + +msgid "Copy r&aw screenshot" +msgstr "Skopírovať s&urovú snímku obrazovky" + +msgid "Copy raw screenshot" +msgstr "Skopírovať surovú snímku obrazovky" + msgid "S&ound" msgstr "&Zvuk" -msgid "&Preferences..." -msgstr "&Predvoľby..." +msgid "&Preferences…" +msgstr "&Predvoľby…" msgid "Enable &Discord integration" msgstr "Povolenie integrácie s &Discordem" -msgid "Sound &gain..." -msgstr "&Zosilnenie zvuku..." +msgid "Sound &gain…" +msgstr "&Zosilnenie zvuku…" msgid "Begin trace" msgstr "Začať trace" @@ -231,20 +252,20 @@ msgstr "Zastaviť trace" msgid "&Help" msgstr "&Pomoc" -msgid "&Documentation..." -msgstr "&Dokumentácia..." +msgid "&Documentation…" +msgstr "&Dokumentácia…" -msgid "&About 86Box..." -msgstr "&O programu 86Box..." +msgid "&About 86Box…" +msgstr "&O programu 86Box…" -msgid "&New image..." -msgstr "&Nový obraz..." +msgid "&New image…" +msgstr "&Nový obraz…" -msgid "&Existing image..." -msgstr "&Existujúci obraz..." +msgid "&Existing image…" +msgstr "&Existujúci obraz…" -msgid "Existing image (&Write-protected)..." -msgstr "Existujúci obraz (&ochrana proti zápisu)..." +msgid "Existing image (&Write-protected)…" +msgstr "Existujúci obraz (&ochrana proti zápisu)…" msgid "&Record" msgstr "&Nahrávať" @@ -261,11 +282,11 @@ msgstr "Previnuť na &koniec" msgid "E&ject" msgstr "&Vystrihnúť" -msgid "&Image..." -msgstr "&Obraz..." +msgid "&Image…" +msgstr "&Obraz…" -msgid "E&xport to 86F..." -msgstr "E&xportovať do 86F..." +msgid "E&xport to 86F…" +msgstr "E&xportovať do 86F…" msgid "&Mute" msgstr "&Stíšiť" @@ -276,8 +297,8 @@ msgstr "&Vystrihnúť" msgid "Reload previous image" msgstr "Načítať znova predchádzajúci obraz" -msgid "&Folder..." -msgstr "&Zložka..." +msgid "&Folder…" +msgstr "&Zložka…" msgid "Preferences" msgstr "Predvoľby" @@ -423,17 +444,17 @@ msgstr "Joystick:" msgid "Joystick" msgstr "Joystick" -msgid "Joystick 1..." -msgstr "Joystick 1..." +msgid "Joystick 1…" +msgstr "Joystick 1…" -msgid "Joystick 2..." -msgstr "Joystick 2..." +msgid "Joystick 2…" +msgstr "Joystick 2…" -msgid "Joystick 3..." -msgstr "Joystick 3..." +msgid "Joystick 3…" +msgstr "Joystick 3…" -msgid "Joystick 4..." -msgstr "Joystick 4..." +msgid "Joystick 4…" +msgstr "Joystick 4…" msgid "Sound card #1:" msgstr "Zvuková karta 1:" @@ -522,10 +543,10 @@ msgstr "Povoliť port LPT3" msgid "Parallel port 4" msgstr "Povoliť port LPT4" -msgid "FD Controller:" +msgid "Floppy disk controller:" msgstr "Disketový radič:" -msgid "CD-ROM Controller:" +msgid "CD-ROM controller:" msgstr "Radič CD-ROM:" msgid "Tertiary IDE Controller" @@ -534,11 +555,11 @@ msgstr "Tretí radič IDE" msgid "Quaternary IDE Controller" msgstr "Štvrtý radič IDE" -msgid "Hard disk" -msgstr "Pevný disk" +msgid "Hard disk controllers" +msgstr "Radiče pevných diskov" -msgid "SCSI" -msgstr "SCSI" +msgid "SCSI controllers" +msgstr "Radiče SCSI" msgid "Controller 1:" msgstr "Radič 1:" @@ -561,11 +582,11 @@ msgstr "Pevné disky:" msgid "Firmware Version" msgstr "Verzia firmvéru" -msgid "&New..." -msgstr "&Nový..." +msgid "&New…" +msgstr "&Nový…" -msgid "&Existing..." -msgstr "&Existujúcý..." +msgid "&Existing…" +msgstr "&Existujúcý…" msgid "&Remove" msgstr "&Odobrať" @@ -873,9 +894,6 @@ msgstr "Ovládač so 4 tlačidlami" msgid "6-button gamepad" msgstr "Ovládač so 6 tlačidlami" -msgid "Gravis PC GamePad" -msgstr "Gravis PC GamePad" - msgid "2-button flight yoke" msgstr "Letecký knipl s 2 tlačidlami" @@ -903,51 +921,6 @@ msgstr "Volant (3 osy, 3 tlačítka)" msgid "Steering wheel (3-axis, 4-button)" msgstr "Volant (3 osy, 4 tlačítka)" -msgid "CH Flightstick" -msgstr "CH Flightstick" - -msgid "CH Flightstick + CH Pedals" -msgstr "CH Flightstick + CH Pedals" - -msgid "CH Flightstick + CH Pedals Pro" -msgstr "CH Flightstick + CH Pedals Pro" - -msgid "CH Flightstick Pro" -msgstr "CH Flightstick Pro" - -msgid "CH Flightstick Pro + CH Pedals" -msgstr "CH Flightstick Pro + CH Pedals" - -msgid "CH Flightstick Pro + CH Pedals Pro" -msgstr "CH Flightstick Pro + CH Pedals Pro" - -msgid "CH Virtual Pilot" -msgstr "CH Virtual Pilot" - -msgid "CH Virtual Pilot + CH Pedals" -msgstr "CH Virtual Pilot + CH Pedals" - -msgid "CH Virtual Pilot + CH Pedals Pro" -msgstr "CH Virtual Pilot + CH Pedals Pro" - -msgid "CH Virtual Pilot Pro" -msgstr "CH Virtual Pilot Pro" - -msgid "CH Virtual Pilot Pro + CH Pedals" -msgstr "CH Virtual Pilot Pro + CH Pedals" - -msgid "CH Virtual Pilot Pro + CH Pedals Pro" -msgstr "CH Virtual Pilot Pro + CH Pedals Pro" - -msgid "Microsoft SideWinder Pad" -msgstr "Microsoft SideWinder Pad" - -msgid "Thrustmaster Flight Control System" -msgstr "Thrustmaster Flight Control System" - -msgid "Thrustmaster FCS + Rudder Control System" -msgstr "Thrustmaster FCS + Rudder Control System" - msgid "Thrustmaster Formula T1/T2 with adapter" msgstr "Thrustmaster Formula T1/T2 s adaptérom" @@ -1002,11 +975,17 @@ msgstr "Vstavané zariadenie" msgid "&File" msgstr "&Súbor" -msgid "&New machine..." -msgstr "&Nový počítač..." +msgid "&New machine…" +msgstr "&Nový počítač…" + +msgid "New machine…" +msgstr "Nový počítač…" + +msgid "New machine" +msgstr "Nový počítač" -msgid "&Check for updates..." -msgstr "&Skontroluj aktualizácie..." +msgid "&Check for updates…" +msgstr "&Skontroluj aktualizácie…" msgid "Exit" msgstr "Ukončiť" @@ -1176,8 +1155,8 @@ msgstr "Nie je možné otvoriť vybraný konfiguračný súbor na čítanie: %1" msgid "Use regular expressions in search box" msgstr "Použiť v poli vyhľadávania regulárne výrazy" -msgid "%1 machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" -msgstr "%1 počítač(ov) je stále aktívnych. Naozaj chcete ukončiť správcu virtuálnych počítačov?" +msgid "%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" +msgstr "%n počítač(ov) je stále aktívnych. Naozaj chcete ukončiť správcu virtuálnych počítačov?" msgid "Add new system wizard" msgstr "Sprievodca pridávaním nového systému" @@ -1257,26 +1236,23 @@ msgstr "Nastaviť zobrazené meno" msgid "Enter the new display name (blank to reset)" msgstr "Zadajte nové zobrazené meno (prázdne pole pre vymazanie)" -msgid "Change &display name..." -msgstr "Zmeniť &zobrazené meno..." +msgid "Change &display name…" +msgstr "Zmeniť &zobrazené meno…" -msgid "Context Menu" -msgstr "Kontextové menu" +msgid "&Open folder…" +msgstr "&Otvoriť priečinok…" -msgid "&Open folder..." -msgstr "&Otvoriť priečinok..." +msgid "Open p&rinter tray…" +msgstr "Otvoriť zásobník &tlačiarne…" -msgid "Open p&rinter tray..." -msgstr "Otvoriť zásobník &tlačiarne..." - -msgid "Set &icon..." -msgstr "Nastaviť &ikonu..." +msgid "Set &icon…" +msgstr "Nastaviť &ikonu…" msgid "Select an icon" msgstr "Vyberte ikonu" -msgid "C&lone..." -msgstr "K&lonovať..." +msgid "C&lone…" +msgstr "K&lonovať…" msgid "Virtual machine \"%1\" (%2) will be cloned into:" msgstr "Virtuálny počítač \"%1\" (%2) bude klonovaný do:" @@ -1362,8 +1338,8 @@ msgstr "Žiadny snímok obrazovky" msgid "Search" msgstr "Hľadať" -msgid "Searching for VMs..." -msgstr "Hľadanie virtuálnych počítačov..." +msgid "Searching for VMs…" +msgstr "Hľadanie virtuálnych počítačov…" msgid "Found %1" msgstr "Nájdené %1" @@ -1398,11 +1374,11 @@ msgstr "Pevný disk (%1)" msgid "MFM/RLL or ESDI CD-ROM drives never existed" msgstr "CD-ROM mechaniky pre rozhranie MFM/RLL alebo ESDI nikdy neexistovali" -msgid "Custom..." -msgstr "Vlastná..." +msgid "Custom…" +msgstr "Vlastná…" -msgid "Custom (large)..." -msgstr "Vlastná (veľká)..." +msgid "Custom (large)…" +msgstr "Vlastná (veľká)…" msgid "Add New Hard Disk" msgstr "Pridať nový pevný disk" @@ -1521,21 +1497,6 @@ msgstr "Časové pečiatky nadradeného a podradeného disku nesúhlasia" msgid "Could not fix VHD timestamp." msgstr "Nebolo možné opraviť časovú pečiatku VHD." -msgid "MFM/RLL" -msgstr "MFM/RLL" - -msgid "XTA" -msgstr "XTA" - -msgid "ESDI" -msgstr "ESDI" - -msgid "IDE" -msgstr "IDE" - -msgid "ATAPI" -msgstr "ATAPI" - msgid "CD-ROM %1 (%2): %3" msgstr "CD-ROM %1 (%2): %3" @@ -1686,14 +1647,14 @@ msgstr "Nástroj pre tablety" msgid "About &Qt" msgstr "O &Qt" -msgid "&MCA devices..." -msgstr "Zariadenia MCA..." +msgid "&MCA devices…" +msgstr "Zariadenia MCA…" msgid "Show non-&primary monitors" msgstr "Zobrazenie iných ako primárnych monitorov" -msgid "Open screenshots &folder..." -msgstr "Otvorte priečinok so snímkami obrazovky..." +msgid "Open screenshots &folder…" +msgstr "Otvorte priečinok so snímkami obrazovky…" msgid "Appl&y fullscreen stretch mode when maximized" msgstr "Použitie režimu roztiahnutia na celú obrazovku pri maximalizácii" @@ -1713,8 +1674,8 @@ msgstr "&Pripojené" msgid "Clear image &history" msgstr "Vymazanie histórie obrázkov" -msgid "Create..." -msgstr "Vytvorte..." +msgid "Create…" +msgstr "Vytvorte…" msgid "Host CD/DVD Drive (%1)" msgstr "Jednotka CD/DVD hostiteľa (%1)" @@ -1755,8 +1716,8 @@ msgstr "Shadery" msgid "Remove" msgstr "Odstránenie stránky" -msgid "Browse..." -msgstr "Prehľadávať..." +msgid "Browse…" +msgstr "Prehľadávať…" msgid "Couldn't create OpenGL context." msgstr "Nepodarilo sa vytvoriť kontext OpenGL." @@ -1845,8 +1806,8 @@ msgstr "Priechod sériového portu 3" msgid "Serial port passthrough 4" msgstr "Priechod cez sériový port 4" -msgid "Renderer &options..." -msgstr "Možnosti vykresľovača..." +msgid "Renderer &options…" +msgstr "Možnosti vykresľovača…" msgid "PC/XT Keyboard" msgstr "Klávesnica PC/XT" @@ -1899,8 +1860,8 @@ msgstr "3M MicroTouch (sériová)" msgid "Default Baud rate" msgstr "Východná prenosová rýchlosť" -msgid "[COM] Standard Hayes-compliant Modem" -msgstr "[COM] Štandardný modem kompatibilný s Hayesom" +msgid "Standard Hayes-compliant Modem" +msgstr "Štandardný modem kompatibilný s Hayesom" msgid "Roland MT-32 Emulation" msgstr "Emulácia Roland MT-32" @@ -1983,6 +1944,9 @@ msgstr "Prerušenie sériového portu" msgid "Parallel port IRQ" msgstr "Prerušenie paralelného portu" +msgid "Hard disk" +msgstr "Pevný disk" + msgid "BIOS Revision" msgstr "Revízia BIOS" @@ -2058,9 +2022,6 @@ msgstr "Priechodnosť vstupu MIDI" msgid "MIDI Clockout" msgstr "Výstup hodín MIDI" -msgid "SoundFont" -msgstr "SoundFont" - msgid "Output Gain" msgstr "Zosilnenie výstupu" @@ -2853,9 +2814,6 @@ msgstr "Prepnúť režim celej obrazovky" msgid "Toggle UI in fullscreen" msgstr "Prepnúť používateľské rozhranie v režime celej obrazovky" -msgid "Screenshot" -msgstr "Zhotoviť snímku obrazovky" - msgid "Release mouse pointer" msgstr "Uvoľniť kurzor myši" @@ -2970,8 +2928,8 @@ msgstr "Navštíviť stránku na stiahnutie" msgid "Update check" msgstr "Kontrola aktualizácií" -msgid "Checking for updates..." -msgstr "Prebieha kontrola aktualizácií..." +msgid "Checking for updates…" +msgstr "Prebieha kontrola aktualizácií…" msgid "86Box Update" msgstr "Aktualizácia 86Box" @@ -3009,8 +2967,8 @@ msgstr "Jas" msgid "Sharpness" msgstr "Ostrota" -msgid "&CGA composite settings..." -msgstr "Nastavenia kompozitného režimu &CGA..." +msgid "&CGA composite settings…" +msgstr "Nastavenia kompozitného režimu &CGA…" msgid "CGA composite settings" msgstr "Nastavenia kompozitného režimu CGA" @@ -3018,8 +2976,8 @@ msgstr "Nastavenia kompozitného režimu CGA" msgid "Monitor EDID" msgstr "EDID monitora" -msgid "Export..." -msgstr "Exportovať..." +msgid "Export…" +msgstr "Exportovať…" msgid "Export EDID" msgstr "Exportovať EDID" @@ -3044,3 +3002,24 @@ msgstr "Tmavá" msgid "Search:" msgstr "Hľadať:" + +msgid "Force interpretation" +msgstr "Vynútiť interpretáciu" + +msgid "Allow recompilation" +msgstr "Povoliť rekompiláciu" + +msgid "&Force interpretation" +msgstr "&Vynútiť interpretáciu" + +msgid "&Allow recompilation" +msgstr "&Povoliť rekompiláciu" + +msgid "&Fast forward" +msgstr "" + +msgid "Fast forward" +msgstr "" + +msgid "To change the system directory, stop all running machines." +msgstr "" diff --git a/src/qt/languages/sl-SI.po b/src/qt/languages/sl-SI.po index b654c988967..64cc6e7eb35 100644 --- a/src/qt/languages/sl-SI.po +++ b/src/qt/languages/sl-SI.po @@ -74,8 +74,8 @@ msgstr "Open&GL (jedro 3.0)" msgid "&VNC" msgstr "&VNC" -msgid "Specify &dimensions..." -msgstr "&Določi velikost..." +msgid "Specify &dimensions…" +msgstr "&Določi velikost…" msgid "Force &4:3 display ratio" msgstr "Vsili razmerje zaslona &4:3" @@ -200,11 +200,11 @@ msgstr "&Mediji" msgid "&Tools" msgstr "&Orodja" -msgid "&Settings..." -msgstr "&Nastavitve..." +msgid "&Settings…" +msgstr "&Nastavitve…" -msgid "Settings..." -msgstr "Nastavitve..." +msgid "Settings…" +msgstr "Nastavitve…" msgid "&Update status bar icons" msgstr "&Posodabljaj ikone statusne vrstice" @@ -212,17 +212,38 @@ msgstr "&Posodabljaj ikone statusne vrstice" msgid "Take s&creenshot" msgstr "&Zajemi posnetek zaslona" +msgid "Take screenshot" +msgstr "Zajemi posnetek zaslona" + +msgid "Take &raw screenshot" +msgstr "Zajemi &neobdelan posnetek zaslona" + +msgid "Take raw screenshot" +msgstr "Zajemi neobdelan posnetek zaslona" + +msgid "C&opy screenshot" +msgstr "K&opiraj posnetek zaslona" + +msgid "Copy screenshot" +msgstr "Kopiraj posnetek zaslona" + +msgid "Copy r&aw screenshot" +msgstr "Kopriaj n&eobdelan posenetk zaslona" + +msgid "Copy raw screenshot" +msgstr "Kopriaj neobdelan posenetk zaslona" + msgid "S&ound" msgstr "Z&vok" -msgid "&Preferences..." -msgstr "&Možnosti..." +msgid "&Preferences…" +msgstr "&Možnosti…" msgid "Enable &Discord integration" msgstr "Omogoči integracijo s programom &Discord" -msgid "Sound &gain..." -msgstr "&Ojačanje zvoka..." +msgid "Sound &gain…" +msgstr "&Ojačanje zvoka…" msgid "Begin trace" msgstr "Z&ačni sledenje" @@ -233,20 +254,20 @@ msgstr "&Končaj sledenje" msgid "&Help" msgstr "&Pomoč" -msgid "&Documentation..." -msgstr "&Dokumentacija..." +msgid "&Documentation…" +msgstr "&Dokumentacija…" -msgid "&About 86Box..." -msgstr "&O programu 86Box..." +msgid "&About 86Box…" +msgstr "&O programu 86Box…" -msgid "&New image..." -msgstr "&Nova slika..." +msgid "&New image…" +msgstr "&Nova slika…" -msgid "&Existing image..." -msgstr "&Obstoječa slika..." +msgid "&Existing image…" +msgstr "&Obstoječa slika…" -msgid "Existing image (&Write-protected)..." -msgstr "Obstoječa slika (&samo za branje)..." +msgid "Existing image (&Write-protected)…" +msgstr "Obstoječa slika (&samo za branje)…" msgid "&Record" msgstr "Snemaj" @@ -263,11 +284,11 @@ msgstr "Preskoči na konec" msgid "E&ject" msgstr "I&zvrzi" -msgid "&Image..." -msgstr "S&lika..." +msgid "&Image…" +msgstr "S&lika…" -msgid "E&xport to 86F..." -msgstr "&Izvozi v 86F..." +msgid "E&xport to 86F…" +msgstr "&Izvozi v 86F…" msgid "&Mute" msgstr "&Utišaj" @@ -278,8 +299,8 @@ msgstr "&Prazen" msgid "Reload previous image" msgstr "Naloži zadnjo sliko" -msgid "&Folder..." -msgstr "&Mapa..." +msgid "&Folder…" +msgstr "&Mapa…" msgid "Preferences" msgstr "Možnosti" @@ -425,17 +446,17 @@ msgstr "Igralna palica:" msgid "Joystick" msgstr "Igralna palica" -msgid "Joystick 1..." -msgstr "Igralna palica 1..." +msgid "Joystick 1…" +msgstr "Igralna palica 1…" -msgid "Joystick 2..." -msgstr "Igralna palica 2..." +msgid "Joystick 2…" +msgstr "Igralna palica 2…" -msgid "Joystick 3..." -msgstr "Igralna palica 3..." +msgid "Joystick 3…" +msgstr "Igralna palica 3…" -msgid "Joystick 4..." -msgstr "Igralna palica 4..." +msgid "Joystick 4…" +msgstr "Igralna palica 4…" msgid "Sound card #1:" msgstr "Zvočna kartica 1:" @@ -524,10 +545,10 @@ msgstr "Vzporedna vrata 3" msgid "Parallel port 4" msgstr "Vzporedna vrata 4" -msgid "FD Controller:" +msgid "Floppy disk controller:" msgstr "Disketni krmilnik:" -msgid "CD-ROM Controller:" +msgid "CD-ROM controller:" msgstr "Krmilnik CD-ROM:" msgid "Tertiary IDE Controller" @@ -536,11 +557,11 @@ msgstr "Terciarni krmilnik IDE" msgid "Quaternary IDE Controller" msgstr "Kvartarni krmilnik IDE" -msgid "Hard disk" -msgstr "Trdi disk" +msgid "Hard disk controllers" +msgstr "Krmilniki trdih diskov" -msgid "SCSI" -msgstr "SCSI" +msgid "SCSI controllers" +msgstr "Krmilniki SCSI" msgid "Controller 1:" msgstr "Krmilnik 1:" @@ -563,11 +584,11 @@ msgstr "Trdi diski:" msgid "Firmware Version" msgstr "Različica programske opreme" -msgid "&New..." -msgstr "Nov..." +msgid "&New…" +msgstr "Nov…" -msgid "&Existing..." -msgstr "Obstoječ..." +msgid "&Existing…" +msgstr "Obstoječ…" msgid "&Remove" msgstr "Odstrani" @@ -875,9 +896,6 @@ msgstr "Igralna ploščica s 4 gumbi" msgid "6-button gamepad" msgstr "Igralna ploščica s 6 gumbi" -msgid "Gravis PC GamePad" -msgstr "Gravis PC GamePad" - msgid "2-button flight yoke" msgstr "Letalski krmilni drog z 2 gumbi" @@ -905,51 +923,6 @@ msgstr "Volan s 3 osmi, 3 gumbi" msgid "Steering wheel (3-axis, 4-button)" msgstr "Volan s 3 osmi, 4 gumbi" -msgid "CH Flightstick" -msgstr "CH Flightstick" - -msgid "CH Flightstick + CH Pedals" -msgstr "CH Flightstick + CH Pedals" - -msgid "CH Flightstick + CH Pedals Pro" -msgstr "CH Flightstick + CH Pedals Pro" - -msgid "CH Flightstick Pro" -msgstr "CH Flightstick Pro" - -msgid "CH Flightstick Pro + CH Pedals" -msgstr "CH Flightstick Pro + CH Pedals" - -msgid "CH Flightstick Pro + CH Pedals Pro" -msgstr "CH Flightstick Pro + CH Pedals Pro" - -msgid "CH Virtual Pilot" -msgstr "CH Virtual Pilot" - -msgid "CH Virtual Pilot + CH Pedals" -msgstr "CH Virtual Pilot + CH Pedals" - -msgid "CH Virtual Pilot + CH Pedals Pro" -msgstr "CH Virtual Pilot + CH Pedals Pro" - -msgid "CH Virtual Pilot Pro" -msgstr "CH Virtual Pilot Pro" - -msgid "CH Virtual Pilot Pro + CH Pedals" -msgstr "CH Virtual Pilot Pro + CH Pedals" - -msgid "CH Virtual Pilot Pro + CH Pedals Pro" -msgstr "CH Virtual Pilot Pro + CH Pedals Pro" - -msgid "Microsoft SideWinder Pad" -msgstr "Microsoft SideWinder Pad" - -msgid "Thrustmaster Flight Control System" -msgstr "Thrustmaster Flight Control System" - -msgid "Thrustmaster FCS + Rudder Control System" -msgstr "Thrustmaster FCS + Rudder Control System" - msgid "Thrustmaster Formula T1/T2 with adapter" msgstr "Thrustmaster Formula T1/T2 s pretvornikom" @@ -1004,11 +977,17 @@ msgstr "Vgrajena naprava" msgid "&File" msgstr "&Datoteka" -msgid "&New machine..." -msgstr "&Nova naprava..." +msgid "&New machine…" +msgstr "&Nova naprava…" + +msgid "New machine…" +msgstr "Nova naprava…" + +msgid "New machine" +msgstr "Nova naprava" -msgid "&Check for updates..." -msgstr "&Preveri obstoj posodobitev..." +msgid "&Check for updates…" +msgstr "&Preveri obstoj posodobitev…" msgid "Exit" msgstr "Izhod" @@ -1178,8 +1157,8 @@ msgstr "Ni bilo mogože odpreti izbrane datoteke z nastavitvami za branje: %1" msgid "Use regular expressions in search box" msgstr "V iskalnem polju uporabi regularne ekspresije" -msgid "%1 machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" -msgstr "Št. trenutno dejavnih naprav je %1. Ali vseeno želite izstopiti iz upravitelja navideznih naprav?" +msgid "%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" +msgstr "Št. trenutno dejavnih naprav je %n. Ali vseeno želite izstopiti iz upravitelja navideznih naprav?" msgid "Add new system wizard" msgstr "Čarovnik za dodajanje novega sistema" @@ -1259,26 +1238,23 @@ msgstr "Nastavi prikazano ime" msgid "Enter the new display name (blank to reset)" msgstr "Vstavi novo prikazano ime (prazno za ponastavitev)" -msgid "Change &display name..." -msgstr "Spremeni &prikazano ime..." +msgid "Change &display name…" +msgstr "Spremeni &prikazano ime…" -msgid "Context Menu" -msgstr "Kontekstni meni" +msgid "&Open folder…" +msgstr "&Odpri mapo…" -msgid "&Open folder..." -msgstr "&Odpri mapo..." +msgid "Open p&rinter tray…" +msgstr "Odpri pladenj &tiskalnika…" -msgid "Open p&rinter tray..." -msgstr "Odpri pladenj &tiskalnika..." - -msgid "Set &icon..." -msgstr "Izberi &ikono..." +msgid "Set &icon…" +msgstr "Izberi &ikono…" msgid "Select an icon" msgstr "Izberi ikono" -msgid "C&lone..." -msgstr "K&loniraj..." +msgid "C&lone…" +msgstr "K&loniraj…" msgid "Virtual machine \"%1\" (%2) will be cloned into:" msgstr "Navidezna naprava \"%1\" (%2) bo klonirana v:" @@ -1364,8 +1340,8 @@ msgstr "Ni zajemov zaslona" msgid "Search" msgstr "Išči" -msgid "Searching for VMs..." -msgstr "Iskanje navideznih naprav..." +msgid "Searching for VMs…" +msgstr "Iskanje navideznih naprav…" msgid "Found %1" msgstr "%1 najden" @@ -1400,11 +1376,11 @@ msgstr "Trdi disk (%1)" msgid "MFM/RLL or ESDI CD-ROM drives never existed" msgstr "MFM/RLL ali ESDI pogoni CD-ROM niso nikoli obstajali" -msgid "Custom..." -msgstr "Po meri..." +msgid "Custom…" +msgstr "Po meri…" -msgid "Custom (large)..." -msgstr "Po meri (velik)..." +msgid "Custom (large)…" +msgstr "Po meri (velik)…" msgid "Add New Hard Disk" msgstr "Dodaj nov trdi disk" @@ -1523,21 +1499,6 @@ msgstr "Časovna žiga nadrejene in podrejene slike diska se ne ujemata" msgid "Could not fix VHD timestamp." msgstr "Ne morem popraviti časovnega žiga slike VHD." -msgid "MFM/RLL" -msgstr "MFM/RLL" - -msgid "XTA" -msgstr "XTA" - -msgid "ESDI" -msgstr "ESDI" - -msgid "IDE" -msgstr "IDE" - -msgid "ATAPI" -msgstr "ATAPI" - msgid "CD-ROM %1 (%2): %3" msgstr "CD-ROM %1 (%2): %3" @@ -1688,14 +1649,14 @@ msgstr "Orodje za tablico" msgid "About &Qt" msgstr "O programu &Qt" -msgid "&MCA devices..." -msgstr "Naprave MCA..." +msgid "&MCA devices…" +msgstr "Naprave MCA…" msgid "Show non-&primary monitors" msgstr "Prikaži neprimarne monitorje" -msgid "Open screenshots &folder..." -msgstr "Odprite mapo s posnetki zaslona..." +msgid "Open screenshots &folder…" +msgstr "Odprite mapo s posnetki zaslona…" msgid "Appl&y fullscreen stretch mode when maximized" msgstr "Uporabi način celozaslonskega raztezanja v maksimiranem stanju" @@ -1715,8 +1676,8 @@ msgstr "&Povezan" msgid "Clear image &history" msgstr "Počisti zgodovino slik" -msgid "Create..." -msgstr "Ustvari..." +msgid "Create…" +msgstr "Ustvari…" msgid "Host CD/DVD Drive (%1)" msgstr "Gostiteljski pogon CD/DVD (%1)" @@ -1757,8 +1718,8 @@ msgstr "Senčilniki" msgid "Remove" msgstr "Odstrani" -msgid "Browse..." -msgstr "Prerskaj..." +msgid "Browse…" +msgstr "Prerskaj…" msgid "Couldn't create OpenGL context." msgstr "Ni bilo mogoče ustvariti konteksta OpenGL." @@ -1847,8 +1808,8 @@ msgstr "Prepust za serijska vrata 3" msgid "Serial port passthrough 4" msgstr "Prepust za serijska vrata 4" -msgid "Renderer &options..." -msgstr "Možnosti sistema za upodabljanje..." +msgid "Renderer &options…" +msgstr "Možnosti sistema za upodabljanje…" msgid "PC/XT Keyboard" msgstr "Tipkovnica PC/XT" @@ -1901,8 +1862,8 @@ msgstr "3M MicroTouch (serijska)" msgid "Default Baud rate" msgstr "Privzeta baudna hitrost" -msgid "[COM] Standard Hayes-compliant Modem" -msgstr "[COM] Standardni modem v skladen s Hayes" +msgid "Standard Hayes-compliant Modem" +msgstr "Standardni modem v skladen s Hayes" msgid "Roland MT-32 Emulation" msgstr "Emulacija Roland MT-32" @@ -1985,6 +1946,9 @@ msgstr "IRQ serijskih vrat" msgid "Parallel port IRQ" msgstr "IRQ paralelnih vrat" +msgid "Hard disk" +msgstr "Trdi disk" + msgid "BIOS Revision" msgstr "Revizija BIOS-a" @@ -2060,9 +2024,6 @@ msgstr "Prepust vhoda MIDI" msgid "MIDI Clockout" msgstr "Izhod ure MIDI" -msgid "SoundFont" -msgstr "SoundFont" - msgid "Output Gain" msgstr "Ojačanje izhoda" @@ -2855,9 +2816,6 @@ msgstr "Preklopi celozaslonski način" msgid "Toggle UI in fullscreen" msgstr "Preklopi uporabniški vmesnik v načinu polnega zaslona" -msgid "Screenshot" -msgstr "Zajem zaslona" - msgid "Release mouse pointer" msgstr "Izpusti kazalec miške" @@ -2972,8 +2930,8 @@ msgstr "Obišči stran s prenosi" msgid "Update check" msgstr "Preveri obstoj posodobitev" -msgid "Checking for updates..." -msgstr "Poteka preverjanje obstoja posodobitev..." +msgid "Checking for updates…" +msgstr "Poteka preverjanje obstoja posodobitev…" msgid "86Box Update" msgstr "Posodobitev programa 86Box" @@ -3011,8 +2969,8 @@ msgstr "Svetlost" msgid "Sharpness" msgstr "Ostrina" -msgid "&CGA composite settings..." -msgstr "Nastavitve kompozitnega načina &CGA..." +msgid "&CGA composite settings…" +msgstr "Nastavitve kompozitnega načina &CGA…" msgid "CGA composite settings" msgstr "Nastavitve kompozitnega načina CGA" @@ -3020,8 +2978,8 @@ msgstr "Nastavitve kompozitnega načina CGA" msgid "Monitor EDID" msgstr "EDID monitorja" -msgid "Export..." -msgstr "Izvoz..." +msgid "Export…" +msgstr "Izvoz…" msgid "Export EDID" msgstr "Izvoz EDID" @@ -3046,3 +3004,24 @@ msgstr "Temno" msgid "Search:" msgstr "Išči:" + +msgid "Force interpretation" +msgstr "Vsili interpretacijo" + +msgid "Allow recompilation" +msgstr "Dovoli prevajanje" + +msgid "&Force interpretation" +msgstr "&Vsili interpretacijo" + +msgid "&Allow recompilation" +msgstr "&Dovoli prevajanje" + +msgid "&Fast forward" +msgstr "" + +msgid "Fast forward" +msgstr "" + +msgid "To change the system directory, stop all running machines." +msgstr "" diff --git a/src/qt/languages/sv-SE.po b/src/qt/languages/sv-SE.po index ff0774bed8e..f4923591915 100644 --- a/src/qt/languages/sv-SE.po +++ b/src/qt/languages/sv-SE.po @@ -66,8 +66,8 @@ msgstr "Open&GL (3.0 Core)" msgid "&VNC" msgstr "&VNC" -msgid "Specify &dimensions..." -msgstr "Ange &mått..." +msgid "Specify &dimensions…" +msgstr "Ange &mått…" msgid "Force &4:3 display ratio" msgstr "Tvinga &4:3 bildförhållande" @@ -192,11 +192,11 @@ msgstr "&Media" msgid "&Tools" msgstr "&Verktyg" -msgid "&Settings..." -msgstr "&Inställningar..." +msgid "&Settings…" +msgstr "&Inställningar…" -msgid "Settings..." -msgstr "Inställningar..." +msgid "Settings…" +msgstr "Inställningar…" msgid "&Update status bar icons" msgstr "&Uppdatera statusfältets ikoner" @@ -204,17 +204,38 @@ msgstr "&Uppdatera statusfältets ikoner" msgid "Take s&creenshot" msgstr "Tag s&kärmbild" +msgid "Take screenshot" +msgstr "Tag skärmbild" + +msgid "Take &raw screenshot" +msgstr "Tag &rå skärmbild" + +msgid "Take raw screenshot" +msgstr "Tag rå skärmbild" + +msgid "C&opy screenshot" +msgstr "&Kopiera skärmbild" + +msgid "Copy screenshot" +msgstr "Kopiera skärmbild" + +msgid "Copy r&aw screenshot" +msgstr "Kopera r&å skärmbild" + +msgid "Copy raw screenshot" +msgstr "Kopera rå skärmbild" + msgid "S&ound" msgstr "L&jud" -msgid "&Preferences..." -msgstr "&Preferenser..." +msgid "&Preferences…" +msgstr "&Preferenser…" msgid "Enable &Discord integration" msgstr "Aktivera &integration med Discord" -msgid "Sound &gain..." -msgstr "Ljud&förstärkning..." +msgid "Sound &gain…" +msgstr "Ljud&förstärkning…" msgid "Begin trace" msgstr "Börja spårning" @@ -225,20 +246,20 @@ msgstr "Avsluta spårning" msgid "&Help" msgstr "&Hjälp" -msgid "&Documentation..." -msgstr "&Dokumentation..." +msgid "&Documentation…" +msgstr "&Dokumentation…" -msgid "&About 86Box..." -msgstr "&Om 86Box..." +msgid "&About 86Box…" +msgstr "&Om 86Box…" -msgid "&New image..." -msgstr "&Ny avbildning..." +msgid "&New image…" +msgstr "&Ny avbildning…" -msgid "&Existing image..." -msgstr "&Befintlig avbildning..." +msgid "&Existing image…" +msgstr "&Befintlig avbildning…" -msgid "Existing image (&Write-protected)..." -msgstr "Befintlig avbildning (&skrivskyddad)..." +msgid "Existing image (&Write-protected)…" +msgstr "Befintlig avbildning (&skrivskyddad)…" msgid "&Record" msgstr "&Spela in" @@ -255,11 +276,11 @@ msgstr "&Spola fram till slutet" msgid "E&ject" msgstr "M&ata ut" -msgid "&Image..." -msgstr "&Avbildning..." +msgid "&Image…" +msgstr "&Avbildning…" -msgid "E&xport to 86F..." -msgstr "E&xportera till 86F..." +msgid "E&xport to 86F…" +msgstr "E&xportera till 86F…" msgid "&Mute" msgstr "&Tysta" @@ -270,8 +291,8 @@ msgstr "T&om" msgid "Reload previous image" msgstr "Ladda om föregående avbildning" -msgid "&Folder..." -msgstr "&Mapp..." +msgid "&Folder…" +msgstr "&Mapp…" msgid "Preferences" msgstr "Preferenser" @@ -417,17 +438,17 @@ msgstr "Styrspak:" msgid "Joystick" msgstr "Styrspak" -msgid "Joystick 1..." -msgstr "Styrspak 1..." +msgid "Joystick 1…" +msgstr "Styrspak 1…" -msgid "Joystick 2..." -msgstr "Styrspak 2..." +msgid "Joystick 2…" +msgstr "Styrspak 2…" -msgid "Joystick 3..." -msgstr "Styrspak 3..." +msgid "Joystick 3…" +msgstr "Styrspak 3…" -msgid "Joystick 4..." -msgstr "Styrspak 4..." +msgid "Joystick 4…" +msgstr "Styrspak 4…" msgid "Sound card #1:" msgstr "Ljudkort #1:" @@ -516,10 +537,10 @@ msgstr "Parallellport 3" msgid "Parallel port 4" msgstr "Parallellport 4" -msgid "FD Controller:" +msgid "Floppy disk controller:" msgstr "Styrenhet för diskett:" -msgid "CD-ROM Controller:" +msgid "CD-ROM controller:" msgstr "Styrenhet för CD-ROM:" msgid "Tertiary IDE Controller" @@ -528,11 +549,11 @@ msgstr "Tertiär IDE-kontroller" msgid "Quaternary IDE Controller" msgstr "Kvartär IDE-kontroller" -msgid "Hard disk" -msgstr "Hårddisk" +msgid "Hard disk controllers" +msgstr "Hårddiskkontroller" -msgid "SCSI" -msgstr "SCSI" +msgid "SCSI controllers" +msgstr "SCSI-styrenheter" msgid "Controller 1:" msgstr "Styrenhet 1:" @@ -555,11 +576,11 @@ msgstr "Hårddiskar:" msgid "Firmware Version" msgstr "Firmware-version" -msgid "&New..." -msgstr "&Ny..." +msgid "&New…" +msgstr "&Ny…" -msgid "&Existing..." -msgstr "&Befintlig..." +msgid "&Existing…" +msgstr "&Befintlig…" msgid "&Remove" msgstr "&Ta bort" @@ -867,9 +888,6 @@ msgstr "Handkontroll med fyra knappar" msgid "6-button gamepad" msgstr "Handkontroll med sex knappar" -msgid "Gravis PC GamePad" -msgstr "Gravis PC GamePad" - msgid "2-button flight yoke" msgstr "Styrspak med två knappar" @@ -897,51 +915,6 @@ msgstr "ratt (tre axlar, tre knappar)" msgid "Steering wheel (3-axis, 4-button)" msgstr "ratt (tre axlar, fyra knappar)" -msgid "CH Flightstick" -msgstr "CH Flightstick" - -msgid "CH Flightstick + CH Pedals" -msgstr "CH Flightstick + CH-pedaler" - -msgid "CH Flightstick + CH Pedals Pro" -msgstr "CH Flightstick + CH-pedaler Pro" - -msgid "CH Flightstick Pro" -msgstr "CH Flightstick Pro" - -msgid "CH Flightstick Pro + CH Pedals" -msgstr "CH Flightstick Pro + CH-pedaler" - -msgid "CH Flightstick Pro + CH Pedals Pro" -msgstr "CH Flightstick Pro + CH-pedaler Pro" - -msgid "CH Virtual Pilot" -msgstr "CH Virtual Pilot" - -msgid "CH Virtual Pilot + CH Pedals" -msgstr "CH Virtual Pilot + CH-pedaler" - -msgid "CH Virtual Pilot + CH Pedals Pro" -msgstr "CH Virtual Pilot + CH-pedaler Pro" - -msgid "CH Virtual Pilot Pro" -msgstr "CH Virtual Pilot Pro" - -msgid "CH Virtual Pilot Pro + CH Pedals" -msgstr "CH Virtual Pilot Pro + CH-pedaler" - -msgid "CH Virtual Pilot Pro + CH Pedals Pro" -msgstr "CH Virtual Pilot Pro + CH-pedaler Pro" - -msgid "Microsoft SideWinder Pad" -msgstr "Microsoft SideWinder Pad" - -msgid "Thrustmaster Flight Control System" -msgstr "Thrustmaster Flight Control System" - -msgid "Thrustmaster FCS + Rudder Control System" -msgstr "Thrustmaster FCS + Rudder Control System" - msgid "Thrustmaster Formula T1/T2 with adapter" msgstr "Thrustmaster Formula T1/T2 med adapter" @@ -996,11 +969,17 @@ msgstr "Intern enhet" msgid "&File" msgstr "&Fil" -msgid "&New machine..." -msgstr "&Ny maskin..." +msgid "&New machine…" +msgstr "&Ny maskin…" + +msgid "New machine…" +msgstr "Ny maskin…" + +msgid "New machine" +msgstr "Ny maskin" -msgid "&Check for updates..." -msgstr "&Leta efter uppdateringar..." +msgid "&Check for updates…" +msgstr "&Leta efter uppdateringar…" msgid "Exit" msgstr "Avsluta" @@ -1170,8 +1149,8 @@ msgstr "Kunde inte läsa den valda konfigurationsfilen: %1" msgid "Use regular expressions in search box" msgstr "Använd vanliga uttryck i sökfältet" -msgid "%1 machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" -msgstr "%1 maskin(er) är aktiva. Är du säker på att du vill avsluta VM-hanteraren ändå?" +msgid "%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" +msgstr "%n maskin(er) är aktiva. Är du säker på att du vill avsluta VM-hanteraren ändå?" msgid "Add new system wizard" msgstr "Guiden Lägg till nytt system" @@ -1251,26 +1230,23 @@ msgstr "Ställ in visningsnamn" msgid "Enter the new display name (blank to reset)" msgstr "Ange nytt visningsnamn (tom för att återställa)" -msgid "Change &display name..." -msgstr "Ändra &visningsnamn..." +msgid "Change &display name…" +msgstr "Ändra &visningsnamn…" -msgid "Context Menu" -msgstr "Innehållsmeny" +msgid "&Open folder…" +msgstr "&Öppna mapp…" -msgid "&Open folder..." -msgstr "&Öppna mapp..." +msgid "Open p&rinter tray…" +msgstr "Öppna &skrivarfack…" -msgid "Open p&rinter tray..." -msgstr "Öppna &skrivarfack..." - -msgid "Set &icon..." -msgstr "Ställ in &ikon..." +msgid "Set &icon…" +msgstr "Ställ in &ikon…" msgid "Select an icon" msgstr "Välj en ikon" -msgid "C&lone..." -msgstr "K&lona..." +msgid "C&lone…" +msgstr "K&lona…" msgid "Virtual machine \"%1\" (%2) will be cloned into:" msgstr "Virtuell maskin \"%1\" (%2) kommer att klonas till:" @@ -1356,8 +1332,8 @@ msgstr "Inga skärmbilder" msgid "Search" msgstr "Sök" -msgid "Searching for VMs..." -msgstr "Söker efter VM..." +msgid "Searching for VMs…" +msgstr "Söker efter VM…" msgid "Found %1" msgstr "Hittade %1" @@ -1392,11 +1368,11 @@ msgstr "Hårddisk (%1)" msgid "MFM/RLL or ESDI CD-ROM drives never existed" msgstr "MFM/RLL eller ESDI CD-ROM-enheter fanns aldrig" -msgid "Custom..." -msgstr "Egen..." +msgid "Custom…" +msgstr "Egen…" -msgid "Custom (large)..." -msgstr "Egen (stor)..." +msgid "Custom (large)…" +msgstr "Egen (stor)…" msgid "Add New Hard Disk" msgstr "Lägg till ny hårddisk" @@ -1515,21 +1491,6 @@ msgstr "Tidsstämpeln på moders- och dotterdisken stämmer inte överens" msgid "Could not fix VHD timestamp." msgstr "Kunde inte laga tidsstämpeln på VHDn." -msgid "MFM/RLL" -msgstr "MFM/RLL" - -msgid "XTA" -msgstr "XTA" - -msgid "ESDI" -msgstr "ESDI" - -msgid "IDE" -msgstr "IDE" - -msgid "ATAPI" -msgstr "ATAPI" - msgid "CD-ROM %1 (%2): %3" msgstr "CD-ROM %1 (%2): %3" @@ -1680,14 +1641,14 @@ msgstr "Plattverktyg" msgid "About &Qt" msgstr "Om &Qt" -msgid "&MCA devices..." -msgstr "MCA-enheter..." +msgid "&MCA devices…" +msgstr "MCA-enheter…" msgid "Show non-&primary monitors" msgstr "Visa icke-primära skärmar" -msgid "Open screenshots &folder..." -msgstr "Öppna skärmbildsmappen..." +msgid "Open screenshots &folder…" +msgstr "Öppna skärmbildsmappen…" msgid "Appl&y fullscreen stretch mode when maximized" msgstr "Tillämpa sträckläge för helskärm när den är maximerad" @@ -1707,8 +1668,8 @@ msgstr "&Ansluten" msgid "Clear image &history" msgstr "Rensa historik för avbildningar" -msgid "Create..." -msgstr "Skapa..." +msgid "Create…" +msgstr "Skapa…" msgid "Host CD/DVD Drive (%1)" msgstr "Värdenhet för CD/DVD (%1)" @@ -1749,8 +1710,8 @@ msgstr "Shaders" msgid "Remove" msgstr "Ta bort" -msgid "Browse..." -msgstr "Bläddra..." +msgid "Browse…" +msgstr "Bläddra…" msgid "Couldn't create OpenGL context." msgstr "Kunde inte skapa OpenGL-sammanhang." @@ -1839,8 +1800,8 @@ msgstr "Serieport passthrough 3" msgid "Serial port passthrough 4" msgstr "Serieport passthrough 4" -msgid "Renderer &options..." -msgstr "Renderingsalternativ..." +msgid "Renderer &options…" +msgstr "Renderingsalternativ…" msgid "PC/XT Keyboard" msgstr "PC/XT-tangentbord" @@ -1893,8 +1854,8 @@ msgstr "3M MicroTouch (serie)" msgid "Default Baud rate" msgstr "Standard Baudhastighet" -msgid "[COM] Standard Hayes-compliant Modem" -msgstr "[COM] Standard Hayes-kompatibelt modem" +msgid "Standard Hayes-compliant Modem" +msgstr "Standard Hayes-kompatibelt modem" msgid "Roland MT-32 Emulation" msgstr "Roland MT-32 emulering" @@ -1977,6 +1938,9 @@ msgstr "IRQ för serieport" msgid "Parallel port IRQ" msgstr "IRQ för parallelport" +msgid "Hard disk" +msgstr "Hårddisk" + msgid "BIOS Revision" msgstr "BIOS-revision" @@ -2052,9 +2016,6 @@ msgstr "MIDI genom" msgid "MIDI Clockout" msgstr "MIDI utklockning" -msgid "SoundFont" -msgstr "Ljudsnitt" - msgid "Output Gain" msgstr "Förstärkning av utmatning" @@ -2847,9 +2808,6 @@ msgstr "Helskärm" msgid "Toggle UI in fullscreen" msgstr "" -msgid "Screenshot" -msgstr "Skärmbild" - msgid "Release mouse pointer" msgstr "Släpp muspekare" @@ -2964,8 +2922,8 @@ msgstr "Besök nedladdningssida" msgid "Update check" msgstr "Leta efter uppdateringar" -msgid "Checking for updates..." -msgstr "Letar efter uppdateringar..." +msgid "Checking for updates…" +msgstr "Letar efter uppdateringar…" msgid "86Box Update" msgstr "86Box-uppdatering" @@ -3003,8 +2961,8 @@ msgstr "Ljusstyrka" msgid "Sharpness" msgstr "Skärpa" -msgid "&CGA composite settings..." -msgstr "Inställningar för &CGA-kompositläget..." +msgid "&CGA composite settings…" +msgstr "Inställningar för &CGA-kompositläget…" msgid "CGA composite settings" msgstr "Inställningar för CGA-kompositläget" @@ -3012,8 +2970,8 @@ msgstr "Inställningar för CGA-kompositläget" msgid "Monitor EDID" msgstr "EDID för bildskärm" -msgid "Export..." -msgstr "Exportera..." +msgid "Export…" +msgstr "Exportera…" msgid "Export EDID" msgstr "Exportera EDID" @@ -3038,3 +2996,24 @@ msgstr "Mörk" msgid "Search:" msgstr "Sök:" + +msgid "Force interpretation" +msgstr "Tvinga tolkning" + +msgid "Allow recompilation" +msgstr "Tillåt omkompilering" + +msgid "&Force interpretation" +msgstr "&Tvinga tolkning" + +msgid "&Allow recompilation" +msgstr "&Tillåt omkompilering" + +msgid "&Fast forward" +msgstr "" + +msgid "Fast forward" +msgstr "" + +msgid "To change the system directory, stop all running machines." +msgstr "" diff --git a/src/qt/languages/tr-TR.po b/src/qt/languages/tr-TR.po index 02bf881a59d..aad11ffda18 100644 --- a/src/qt/languages/tr-TR.po +++ b/src/qt/languages/tr-TR.po @@ -1,8 +1,14 @@ msgid "" msgstr "" +"PO-Revision-Date: 2026-01-01 20:06+0000\n" +"Last-Translator: Umut Çağan Uçanok \n" +"Language-Team: Turkish \n" +"Language: tr-TR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.12.2\n" "X-Language: tr_TR\n" "X-Source-Language: en_US\n" @@ -66,8 +72,8 @@ msgstr "OpenG&L (Sürüm 3.0)" msgid "&VNC" msgstr "&VNC" -msgid "Specify &dimensions..." -msgstr "Pencere &boyutunu belirle..." +msgid "Specify &dimensions…" +msgstr "Pencere &boyutunu belirle…" msgid "Force &4:3 display ratio" msgstr "&4:3 görüntü oranına zorla" @@ -192,11 +198,11 @@ msgstr "&Ortam" msgid "&Tools" msgstr "&Araçlar" -msgid "&Settings..." -msgstr "&Ayarlar..." +msgid "&Settings…" +msgstr "&Ayarlar…" -msgid "Settings..." -msgstr "Ayarlar..." +msgid "Settings…" +msgstr "Ayarlar…" msgid "&Update status bar icons" msgstr "Durum &çubuğu simgelerini güncelle" @@ -204,17 +210,38 @@ msgstr "Durum &çubuğu simgelerini güncelle" msgid "Take s&creenshot" msgstr "&Ekran görüntüsü al" +msgid "Take screenshot" +msgstr "Ekran görüntüsü al" + +msgid "Take &raw screenshot" +msgstr "Ekran &ham görüntüsü al" + +msgid "Take raw screenshot" +msgstr "Ekran ham görüntüsü al" + +msgid "C&opy screenshot" +msgstr "Ekran görüntüsü k&opyala" + +msgid "Copy screenshot" +msgstr "Ekran görüntüsü kopyala" + +msgid "Copy r&aw screenshot" +msgstr "Ekran h&am görüntüsü kopyala" + +msgid "Copy raw screenshot" +msgstr "Ekran ham görüntüsü kopyala" + msgid "S&ound" msgstr "&Ses" -msgid "&Preferences..." -msgstr "&Tercihler..." +msgid "&Preferences…" +msgstr "&Tercihler…" msgid "Enable &Discord integration" msgstr "&Discord entegrasyonunu etkinleştir" -msgid "Sound &gain..." -msgstr "&Sesi artır..." +msgid "Sound &gain…" +msgstr "&Sesi artır…" msgid "Begin trace" msgstr "İzlemeyi başlat" @@ -225,20 +252,20 @@ msgstr "İzlemeyi bitir" msgid "&Help" msgstr "&Yardım" -msgid "&Documentation..." -msgstr "&Belgeler..." +msgid "&Documentation…" +msgstr "&Belgeler…" -msgid "&About 86Box..." -msgstr "&86Box hakkında..." +msgid "&About 86Box…" +msgstr "&86Box hakkında…" -msgid "&New image..." -msgstr "&Yeni görüntü oluştur..." +msgid "&New image…" +msgstr "&Yeni görüntü oluştur…" -msgid "&Existing image..." -msgstr "&Görüntü seç..." +msgid "&Existing image…" +msgstr "&Görüntü seç…" -msgid "Existing image (&Write-protected)..." -msgstr "Görüntü &seç (Yazma korumalı)..." +msgid "Existing image (&Write-protected)…" +msgstr "Görüntü &seç (Yazma korumalı)…" msgid "&Record" msgstr "&Kaydet" @@ -255,11 +282,11 @@ msgstr "Sona &doğru sar" msgid "E&ject" msgstr "&Çıkar" -msgid "&Image..." -msgstr "&Görüntü seç..." +msgid "&Image…" +msgstr "&Görüntü seç…" -msgid "E&xport to 86F..." -msgstr "&86F olarak kaydet..." +msgid "E&xport to 86F…" +msgstr "&86F olarak kaydet…" msgid "&Mute" msgstr "&Sessize al" @@ -270,8 +297,8 @@ msgstr "Görüntüyü &çıkar" msgid "Reload previous image" msgstr "Önceki görüntüyü yeniden seç" -msgid "&Folder..." -msgstr "&Klasör seç..." +msgid "&Folder…" +msgstr "&Klasör seç…" msgid "Preferences" msgstr "Tercihler" @@ -417,17 +444,17 @@ msgstr "Oyun Kolu:" msgid "Joystick" msgstr "Oyun Kolu" -msgid "Joystick 1..." -msgstr "1. Oyun Kolu..." +msgid "Joystick 1…" +msgstr "1. Oyun Kolu…" -msgid "Joystick 2..." -msgstr "2. Oyun Kolu..." +msgid "Joystick 2…" +msgstr "2. Oyun Kolu…" -msgid "Joystick 3..." -msgstr "3. Oyun Kolu..." +msgid "Joystick 3…" +msgstr "3. Oyun Kolu…" -msgid "Joystick 4..." -msgstr "4. Oyun Kolu..." +msgid "Joystick 4…" +msgstr "4. Oyun Kolu…" msgid "Sound card #1:" msgstr "1. Ses Kartı:" @@ -516,23 +543,23 @@ msgstr "3. Paralel bağlantı noktası" msgid "Parallel port 4" msgstr "4. Paralel bağlantı noktası" -msgid "FD Controller:" -msgstr "Disket Denetleyicisi:" +msgid "Floppy disk controller:" +msgstr "Disket denetleyicisi:" -msgid "CD-ROM Controller:" -msgstr "CD-ROM Denetleyicisi:" +msgid "CD-ROM controller:" +msgstr "CD-ROM denetleyicisi:" msgid "Tertiary IDE Controller" -msgstr "Üçüncül IDE Denetleyicisi" +msgstr "Üçüncül IDE denetleyicisi" msgid "Quaternary IDE Controller" -msgstr "Dördüncül IDE Denetleyicisi" +msgstr "Dördüncül IDE denetleyicisi" -msgid "Hard disk" -msgstr "Sabit disk" +msgid "Hard disk controllers" +msgstr "Sabit disk denetleyicileri" -msgid "SCSI" -msgstr "SCSI" +msgid "SCSI controllers" +msgstr "SCSI denetleyicileri" msgid "Controller 1:" msgstr "1. Denetleyici:" @@ -555,11 +582,11 @@ msgstr "Sabit diskler:" msgid "Firmware Version" msgstr "Bellenim Sürümü" -msgid "&New..." -msgstr "&Yeni görüntü oluştur..." +msgid "&New…" +msgstr "&Yeni görüntü oluştur…" -msgid "&Existing..." -msgstr "&Görüntü dosyası seç..." +msgid "&Existing…" +msgstr "&Görüntü dosyası seç…" msgid "&Remove" msgstr "&Kaldır" @@ -867,9 +894,6 @@ msgstr "4 düğmeli oyun tablası" msgid "6-button gamepad" msgstr "6 düğmeli oyun tablası" -msgid "Gravis PC GamePad" -msgstr "Gravis PC GamePad" - msgid "2-button flight yoke" msgstr "2 düğmeli uçuş dümeni" @@ -897,51 +921,6 @@ msgstr "direksiyonu (3 eksenli, 3 düğmeli)" msgid "Steering wheel (3-axis, 4-button)" msgstr "direksiyonu (3 eksenli, 4 düğmeli)" -msgid "CH Flightstick" -msgstr "CH Flightstick" - -msgid "CH Flightstick + CH Pedals" -msgstr "CH Flightstick + CH Pedals" - -msgid "CH Flightstick + CH Pedals Pro" -msgstr "CH Flightstick + CH Pedals Pro" - -msgid "CH Flightstick Pro" -msgstr "CH Flightstick Pro" - -msgid "CH Flightstick Pro + CH Pedals" -msgstr "CH Flightstick Pro + CH Pedals" - -msgid "CH Flightstick Pro + CH Pedals Pro" -msgstr "CH Flightstick Pro + CH Pedals Pro" - -msgid "CH Virtual Pilot" -msgstr "CH Virtual Pilot" - -msgid "CH Virtual Pilot + CH Pedals" -msgstr "CH Virtual Pilot + CH Pedals" - -msgid "CH Virtual Pilot + CH Pedals Pro" -msgstr "CH Virtual Pilot + CH Pedals Pro" - -msgid "CH Virtual Pilot Pro" -msgstr "CH Virtual Pilot Pro" - -msgid "CH Virtual Pilot Pro + CH Pedals" -msgstr "CH Virtual Pilot Pro + CH Pedals" - -msgid "CH Virtual Pilot Pro + CH Pedals Pro" -msgstr "CH Virtual Pilot Pro + CH Pedals Pro" - -msgid "Microsoft SideWinder Pad" -msgstr "Microsoft SideWinder Pad" - -msgid "Thrustmaster Flight Control System" -msgstr "Thrustmaster Flight Control System" - -msgid "Thrustmaster FCS + Rudder Control System" -msgstr "Thrustmaster FCS + Rudder Control System" - msgid "Thrustmaster Formula T1/T2 with adapter" msgstr "Adaptörlü Thrustmaster Formula T1/T2" @@ -996,11 +975,17 @@ msgstr "Dahili cihaz" msgid "&File" msgstr "&Dosya" -msgid "&New machine..." -msgstr "&Yeni makine..." +msgid "&New machine…" +msgstr "&Yeni makine…" + +msgid "New machine…" +msgstr "Yeni makine…" + +msgid "New machine" +msgstr "Yeni makine" -msgid "&Check for updates..." -msgstr "&Güncelleştirmeleri kontrol et..." +msgid "&Check for updates…" +msgstr "&Güncelleştirmeleri kontrol et…" msgid "Exit" msgstr "Çıkış yap" @@ -1170,8 +1155,8 @@ msgstr "Seçili yapılandırma dosyası okunmak için açılamıyor: %1" msgid "Use regular expressions in search box" msgstr "Arama kutusunda düzenli ifadeler kullan" -msgid "%1 machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" -msgstr "%1 makine şu anda aktif. Yine de VM yöneticisinden çıkmak istediğinize emin misiniz?" +msgid "%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" +msgstr "%n makine şu anda aktif. Yine de VM yöneticisinden çıkmak istediğinize emin misiniz?" msgid "Add new system wizard" msgstr "Yeni sistem ekleme sihirbazı" @@ -1251,26 +1236,23 @@ msgstr "Görüntü adını ayarla" msgid "Enter the new display name (blank to reset)" msgstr "Yeni görünü adını girin (sıfırlamak için boş bırakın)" -msgid "Change &display name..." -msgstr "Görüntü adını &değiştirin..." +msgid "Change &display name…" +msgstr "Görüntü adını &değiştirin…" -msgid "Context Menu" -msgstr "Bağlam Menüsü" +msgid "&Open folder…" +msgstr "Klas&örü aç…" -msgid "&Open folder..." -msgstr "Klas&örü aç..." +msgid "Open p&rinter tray…" +msgstr "Yazıcı te&psisini aç…" -msgid "Open p&rinter tray..." -msgstr "Yazıcı te&psisini aç..." - -msgid "Set &icon..." -msgstr "S&imge seç..." +msgid "Set &icon…" +msgstr "S&imge seç…" msgid "Select an icon" msgstr "Bir simge seç" -msgid "C&lone..." -msgstr "K&lonla..." +msgid "C&lone…" +msgstr "K&lonla…" msgid "Virtual machine \"%1\" (%2) will be cloned into:" msgstr "Sanal makine \"%1\" (%2) şuraya klonlanacaktır:" @@ -1356,8 +1338,8 @@ msgstr "Ekran görüntüsü yok" msgid "Search" msgstr "Ara" -msgid "Searching for VMs..." -msgstr "VM'ler aranıyor..." +msgid "Searching for VMs…" +msgstr "VM'ler aranıyor…" msgid "Found %1" msgstr "%1 bulundu" @@ -1392,11 +1374,11 @@ msgstr "Sabit disk (%1)" msgid "MFM/RLL or ESDI CD-ROM drives never existed" msgstr "MFM/RLL veya ESDI CD-ROM sürücüleri hiçbir zaman kullanılmamıştır" -msgid "Custom..." -msgstr "Diğer..." +msgid "Custom…" +msgstr "Diğer…" -msgid "Custom (large)..." -msgstr "Diğer (büyük)..." +msgid "Custom (large)…" +msgstr "Diğer (büyük)…" msgid "Add New Hard Disk" msgstr "Yeni Sabit Disk Görüntüsü Oluştur" @@ -1515,21 +1497,6 @@ msgstr "Ana ve ek disklerin zaman damgaları uyuşmuyor" msgid "Could not fix VHD timestamp." msgstr "VHD'nin zaman damgası düzeltilemedi." -msgid "MFM/RLL" -msgstr "MFM/RLL" - -msgid "XTA" -msgstr "XTA" - -msgid "ESDI" -msgstr "ESDI" - -msgid "IDE" -msgstr "IDE" - -msgid "ATAPI" -msgstr "ATAPI" - msgid "CD-ROM %1 (%2): %3" msgstr "CD-ROM %1 (%2): %3" @@ -1680,14 +1647,14 @@ msgstr "Tablet aracı" msgid "About &Qt" msgstr "&Qt hakkında" -msgid "&MCA devices..." -msgstr "MCA cihazları..." +msgid "&MCA devices…" +msgstr "MCA cihazları…" msgid "Show non-&primary monitors" msgstr "Birincil olmayan monitörleri göster" -msgid "Open screenshots &folder..." -msgstr "Ekran görüntüsü klasörünü aç..." +msgid "Open screenshots &folder…" +msgstr "Ekran görüntüsü klasörünü aç…" msgid "Appl&y fullscreen stretch mode when maximized" msgstr "Büyütüldüğünde tam ekran germe modunu uygula" @@ -1707,8 +1674,8 @@ msgstr "&Bağlı" msgid "Clear image &history" msgstr "Görüntü geçmişini temizle" -msgid "Create..." -msgstr "Oluştur..." +msgid "Create…" +msgstr "Oluştur…" msgid "Host CD/DVD Drive (%1)" msgstr "Ana bilgisayar CD/DVD sürücüsü (%1)" @@ -1749,8 +1716,8 @@ msgstr "Gölgelendiriciler" msgid "Remove" msgstr "Kaldır" -msgid "Browse..." -msgstr "Göz at..." +msgid "Browse…" +msgstr "Göz at…" msgid "Couldn't create OpenGL context." msgstr "OpenGL bağlamı oluşturulamadı." @@ -1819,7 +1786,7 @@ msgid "VDE Socket:" msgstr "VDE Soketi:" msgid "TAP Bridge Device:" -msgstr "" +msgstr "TAP Köprü Cihazı:" msgid "86Box Unit Tester" msgstr "86Box Test Cihazı" @@ -1839,8 +1806,8 @@ msgstr "3. Seri bağlantı noktası geçişi" msgid "Serial port passthrough 4" msgstr "4. Seri bağlantı noktası geçişi" -msgid "Renderer &options..." -msgstr "Derleyici seçenekleri..." +msgid "Renderer &options…" +msgstr "Derleyici seçenekleri…" msgid "PC/XT Keyboard" msgstr "PC/XT Klavyesi" @@ -1858,7 +1825,7 @@ msgid "PS/55 Keyboard" msgstr "PS/55 Klavyesi" msgid "Keys" -msgstr "Keys" +msgstr "Tuşlar" msgid "Logitech/Microsoft Bus Mouse" msgstr "Logitech/Microsoft Bus Faresi" @@ -1893,8 +1860,8 @@ msgstr "3M MicroTouch (seri)" msgid "Default Baud rate" msgstr "Varsayılan Baud hızı" -msgid "[COM] Standard Hayes-compliant Modem" -msgstr "[COM] Standart Hayes Uyumlu Modem" +msgid "Standard Hayes-compliant Modem" +msgstr "Standart Hayes Uyumlu Modem" msgid "Roland MT-32 Emulation" msgstr "Roland MT-32 Emülasyonu" @@ -1977,6 +1944,9 @@ msgstr "Seri bağlantı noktası IRQ'su" msgid "Parallel port IRQ" msgstr "Paralel bağlantı noktası IRQ'su" +msgid "Hard disk" +msgstr "Sabit disk" + msgid "BIOS Revision" msgstr "BIOS Revizyonu" @@ -2052,9 +2022,6 @@ msgstr "MIDI Geçişi" msgid "MIDI Clockout" msgstr "MIDI Saat Çıkışı" -msgid "SoundFont" -msgstr "SoundFont" - msgid "Output Gain" msgstr "Çıkış Sesi Artışı" @@ -2101,7 +2068,7 @@ msgid "Reverb Output Gain" msgstr "Yankı Çıkış Sesi Artışı" msgid "Reversed stereo" -msgstr "Tersine çevirilmiş stereo" +msgstr "Tersine çevrilmiş stereo" msgid "Nice ramp" msgstr "Güzel rampa" @@ -2212,16 +2179,16 @@ msgid "WSS DMA" msgstr "WSS DMA" msgid "RTC IRQ" -msgstr "" +msgstr "RTC IRQ" msgid "RTC Port Address" -msgstr "" +msgstr "RTC Bağlantı Noktası Adresi" msgid "Onboard RTC" -msgstr "" +msgstr "Yerleşik RTC" msgid "Not installed" -msgstr "" +msgstr "Kurulu değil" msgid "Enable OPL" msgstr "OPL'yi etkinleştir" @@ -2845,10 +2812,7 @@ msgid "Toggle fullscreen" msgstr "Tam ekran modunu ayarla" msgid "Toggle UI in fullscreen" -msgstr "" - -msgid "Screenshot" -msgstr "Ekran görüntüsü" +msgstr "Arayüzü tam ekranda ayarla" msgid "Release mouse pointer" msgstr "Fare imlecini serbest bırak" @@ -2964,8 +2928,8 @@ msgstr "İndirme sayfasını ziyaret et" msgid "Update check" msgstr "Güncelleme kontrolü" -msgid "Checking for updates..." -msgstr "Güncellemeler kontrol ediliyor..." +msgid "Checking for updates…" +msgstr "Güncellemeler kontrol ediliyor…" msgid "86Box Update" msgstr "86Box Güncellemesi" @@ -3003,8 +2967,8 @@ msgstr "Parlaklık" msgid "Sharpness" msgstr "Keskinlik" -msgid "&CGA composite settings..." -msgstr "&CGA kompozit modunun ayarları..." +msgid "&CGA composite settings…" +msgstr "&CGA kompozit modunun ayarları…" msgid "CGA composite settings" msgstr "CGA kompozit modunun ayarları" @@ -3012,8 +2976,8 @@ msgstr "CGA kompozit modunun ayarları" msgid "Monitor EDID" msgstr "Monitörün EDID'si" -msgid "Export..." -msgstr "Dışa aktar..." +msgid "Export…" +msgstr "Dışa aktar…" msgid "Export EDID" msgstr "EDID'i dışa aktar" @@ -3038,3 +3002,24 @@ msgstr "Karanlık" msgid "Search:" msgstr "Ara:" + +msgid "Force interpretation" +msgstr "Yorumlanmasını zorla" + +msgid "Allow recompilation" +msgstr "Derlenmesine izin ver" + +msgid "&Force interpretation" +msgstr "&Yorumlanmasını zorla" + +msgid "&Allow recompilation" +msgstr "&Derlenmesine izin ver" + +msgid "&Fast forward" +msgstr "" + +msgid "Fast forward" +msgstr "" + +msgid "To change the system directory, stop all running machines." +msgstr "" diff --git a/src/qt/languages/uk-UA.po b/src/qt/languages/uk-UA.po index e98da1f0c76..7fd0d0b3325 100644 --- a/src/qt/languages/uk-UA.po +++ b/src/qt/languages/uk-UA.po @@ -74,8 +74,8 @@ msgstr "Open&GL (3.0 Core)" msgid "&VNC" msgstr "&VNC" -msgid "Specify &dimensions..." -msgstr "&Вказати розміри..." +msgid "Specify &dimensions…" +msgstr "&Вказати розміри…" msgid "Force &4:3 display ratio" msgstr "Встановити відношення сторін &4:3" @@ -200,29 +200,50 @@ msgstr "&Носії" msgid "&Tools" msgstr "&Інструменти" -msgid "&Settings..." -msgstr "&Налаштування машини..." +msgid "&Settings…" +msgstr "&Налаштування машини…" -msgid "Settings..." -msgstr "Налаштування машини..." +msgid "Settings…" +msgstr "Налаштування машини…" msgid "&Update status bar icons" msgstr "&Обновлення значків рядка стану" msgid "Take s&creenshot" -msgstr "Зробити &знімок" +msgstr "&Зробити скріншот" + +msgid "Take screenshot" +msgstr "Зробити скріншот" + +msgid "Take &raw screenshot" +msgstr "Зробити &сирий скріншот" + +msgid "Take raw screenshot" +msgstr "Зробити сирий скріншот" + +msgid "C&opy screenshot" +msgstr "С&копійовати скріншот" + +msgid "Copy screenshot" +msgstr "Скопійовати скріншот" + +msgid "Copy r&aw screenshot" +msgstr "Скопійовати с&ирий скріншот" + +msgid "Copy raw screenshot" +msgstr "Скопійовати сирий скріншот" msgid "S&ound" msgstr "&Звук" -msgid "&Preferences..." -msgstr "&Параметри..." +msgid "&Preferences…" +msgstr "&Параметри…" msgid "Enable &Discord integration" msgstr "Увімкнути інтеграцію &Discord" -msgid "Sound &gain..." -msgstr "&Посилення звуку..." +msgid "Sound &gain…" +msgstr "&Посилення звуку…" msgid "Begin trace" msgstr "Почати трасування" @@ -233,20 +254,20 @@ msgstr "Завершити трасування" msgid "&Help" msgstr "&Допомога" -msgid "&Documentation..." -msgstr "&Документація..." +msgid "&Documentation…" +msgstr "&Документація…" -msgid "&About 86Box..." -msgstr "&Про програму 86Box..." +msgid "&About 86Box…" +msgstr "&Про програму 86Box…" -msgid "&New image..." -msgstr "&Новий образ..." +msgid "&New image…" +msgstr "&Новий образ…" -msgid "&Existing image..." -msgstr "&Вибрати образ..." +msgid "&Existing image…" +msgstr "&Вибрати образ…" -msgid "Existing image (&Write-protected)..." -msgstr "Вибрати образ (&Захист від запису)..." +msgid "Existing image (&Write-protected)…" +msgstr "Вибрати образ (&Захист від запису)…" msgid "&Record" msgstr "&Запис" @@ -263,11 +284,11 @@ msgstr "&Перемотування у кінець" msgid "E&ject" msgstr "&Вилучити" -msgid "&Image..." -msgstr "&Образ..." +msgid "&Image…" +msgstr "&Образ…" -msgid "E&xport to 86F..." -msgstr "&Експорт в 86F..." +msgid "E&xport to 86F…" +msgstr "&Експорт в 86F…" msgid "&Mute" msgstr "&Відключити звук" @@ -278,8 +299,8 @@ msgstr "&Пустий" msgid "Reload previous image" msgstr "Знову завантажити попередній образ" -msgid "&Folder..." -msgstr "&Тека..." +msgid "&Folder…" +msgstr "&Тека…" msgid "Preferences" msgstr "Параметри" @@ -425,17 +446,17 @@ msgstr "Джойстик:" msgid "Joystick" msgstr "Джойстик" -msgid "Joystick 1..." -msgstr "Джойстик 1..." +msgid "Joystick 1…" +msgstr "Джойстик 1…" -msgid "Joystick 2..." -msgstr "Джойстик 2..." +msgid "Joystick 2…" +msgstr "Джойстик 2…" -msgid "Joystick 3..." -msgstr "Джойстик 3..." +msgid "Joystick 3…" +msgstr "Джойстик 3…" -msgid "Joystick 4..." -msgstr "Джойстик 4..." +msgid "Joystick 4…" +msgstr "Джойстик 4…" msgid "Sound card #1:" msgstr "Звукова карта 1:" @@ -524,23 +545,23 @@ msgstr "Паралельний порт LPT3" msgid "Parallel port 4" msgstr "Паралельний порт LPT4" -msgid "FD Controller:" -msgstr "Контролер FD:" +msgid "Floppy disk controller:" +msgstr "Контролер гнучких дисків:" -msgid "CD-ROM Controller:" +msgid "CD-ROM controller:" msgstr "Контролер CD-ROM:" msgid "Tertiary IDE Controller" -msgstr "Третинний IDE контролер" +msgstr "Третинний контролер IDE" msgid "Quaternary IDE Controller" -msgstr "Четвертинний IDE контролер" +msgstr "Четвертинний контролер IDE" -msgid "Hard disk" -msgstr "Жорсткий диск" +msgid "Hard disk controllers" +msgstr "Контролери жорстких дисків" -msgid "SCSI" -msgstr "SCSI" +msgid "SCSI controllers" +msgstr "Контролери SCSI" msgid "Controller 1:" msgstr "Контролер 1:" @@ -563,11 +584,11 @@ msgstr "Жорсткі диски:" msgid "Firmware Version" msgstr "Версія прошивки" -msgid "&New..." -msgstr "&Створити..." +msgid "&New…" +msgstr "&Створити…" -msgid "&Existing..." -msgstr "&Вибрати..." +msgid "&Existing…" +msgstr "&Вибрати…" msgid "&Remove" msgstr "&Прибрати" @@ -875,9 +896,6 @@ msgstr "4-кнопковий геймпад" msgid "6-button gamepad" msgstr "6-кнопковий геймпад" -msgid "Gravis PC GamePad" -msgstr "Gravis PC GamePad" - msgid "2-button flight yoke" msgstr "2-кнопковий flight yoke" @@ -905,51 +923,6 @@ msgstr "Кермо (3-осьове, 3-кнопкове)" msgid "Steering wheel (3-axis, 4-button)" msgstr "Кермо (3-осьове, 4-кнопкове)" -msgid "CH Flightstick" -msgstr "CH Flightstick" - -msgid "CH Flightstick + CH Pedals" -msgstr "CH Flightstick + CH Педалі" - -msgid "CH Flightstick + CH Pedals Pro" -msgstr "CH Flightstick + CH Педалі Pro" - -msgid "CH Flightstick Pro" -msgstr "CH Flightstick Pro" - -msgid "CH Flightstick Pro + CH Pedals" -msgstr "CH Flightstick Pro + CH Педалі" - -msgid "CH Flightstick Pro + CH Pedals Pro" -msgstr "CH Flightstick Pro + CH Педалі Pro" - -msgid "CH Virtual Pilot" -msgstr "CH Virtual Pilot" - -msgid "CH Virtual Pilot + CH Pedals" -msgstr "CH Virtual Pilot + CH Педалі" - -msgid "CH Virtual Pilot + CH Pedals Pro" -msgstr "CH Virtual Pilot + CH Педалі Pro" - -msgid "CH Virtual Pilot Pro" -msgstr "CH Virtual Pilot Pro" - -msgid "CH Virtual Pilot Pro + CH Pedals" -msgstr "CH Virtual Pilot Pro + CH Педалі" - -msgid "CH Virtual Pilot Pro + CH Pedals Pro" -msgstr "CH Virtual Pilot Pro + CH Педалі Pro" - -msgid "Microsoft SideWinder Pad" -msgstr "Microsoft SideWinder Pad" - -msgid "Thrustmaster Flight Control System" -msgstr "Система управління польотом Thrustmaster" - -msgid "Thrustmaster FCS + Rudder Control System" -msgstr "Thrustmaster FCS + Система управління кермом" - msgid "Thrustmaster Formula T1/T2 with adapter" msgstr "Thrustmaster Formula T1/T2 з адаптером" @@ -1004,11 +977,17 @@ msgstr "Вбудований пристрій" msgid "&File" msgstr "&Файл" -msgid "&New machine..." -msgstr "&Нова машина..." +msgid "&New machine…" +msgstr "&Нова машина…" + +msgid "New machine…" +msgstr "Нова машина…" + +msgid "New machine" +msgstr "Нова машина" -msgid "&Check for updates..." -msgstr "&Перевірити оновлення..." +msgid "&Check for updates…" +msgstr "&Перевірити оновлення…" msgid "Exit" msgstr "Вихід" @@ -1178,8 +1157,8 @@ msgstr "Неможливо відкрити вибраний файл конфі msgid "Use regular expressions in search box" msgstr "Використовувати регулярні вирази в полі пошуку" -msgid "%1 machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" -msgstr "%1 машина(и) наразі активна(і). Ви впевнені, що все одно хочете вийти з менеджера віртуальної машини?" +msgid "%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" +msgstr "%n машина(и) наразі активна(і). Ви впевнені, що все одно хочете вийти з менеджера віртуальної машини?" msgid "Add new system wizard" msgstr "Майстер додавання нової системи" @@ -1259,26 +1238,23 @@ msgstr "Встановити відображуване ім'я" msgid "Enter the new display name (blank to reset)" msgstr "Введіть нове відображуване ім'я (порожнє, щоб скинути)" -msgid "Change &display name..." -msgstr "Змінити &відображуване ім'я..." +msgid "Change &display name…" +msgstr "Змінити &відображуване ім'я…" -msgid "Context Menu" -msgstr "Контекстне меню" +msgid "&Open folder…" +msgstr "&Відкрити папку…" -msgid "&Open folder..." -msgstr "&Відкрити папку..." +msgid "Open p&rinter tray…" +msgstr "Відкрити папку &принтера…" -msgid "Open p&rinter tray..." -msgstr "Відкрити папку &принтера..." - -msgid "Set &icon..." -msgstr "Встановити &значок..." +msgid "Set &icon…" +msgstr "Встановити &значок…" msgid "Select an icon" msgstr "Виберіть значок" -msgid "C&lone..." -msgstr "К&лонувати..." +msgid "C&lone…" +msgstr "К&лонувати…" msgid "Virtual machine \"%1\" (%2) will be cloned into:" msgstr "Віртуальна машина «%1» (%2) буде клонована в:" @@ -1364,8 +1340,8 @@ msgstr "Немає скріншоту" msgid "Search" msgstr "Пошук" -msgid "Searching for VMs..." -msgstr "Пошук віртуальних машин..." +msgid "Searching for VMs…" +msgstr "Пошук віртуальних машин…" msgid "Found %1" msgstr "Знайдено %1" @@ -1400,11 +1376,11 @@ msgstr "Жорсткий диск (%1)" msgid "MFM/RLL or ESDI CD-ROM drives never existed" msgstr "MFM/RLL або ESDI дисководів CD-ROM ніколи не існувало" -msgid "Custom..." -msgstr "Задати вручну..." +msgid "Custom…" +msgstr "Задати вручну…" -msgid "Custom (large)..." -msgstr "Задати вручну (large)..." +msgid "Custom (large)…" +msgstr "Задати вручну (large)…" msgid "Add New Hard Disk" msgstr "Створити новий жорсткий диск" @@ -1464,7 +1440,7 @@ msgid "Don't overwrite" msgstr "Не перезаписувати" msgid "Raw image" -msgstr "RAW образ" +msgstr "Сирий образ" msgid "HDI image" msgstr "Образ HDI" @@ -1523,21 +1499,6 @@ msgstr "Тимчасові мітки батьківського та дочір msgid "Could not fix VHD timestamp." msgstr "Не вдалося виправити тимчасову позначку VHD." -msgid "MFM/RLL" -msgstr "MFM/RLL" - -msgid "XTA" -msgstr "XTA" - -msgid "ESDI" -msgstr "ESDI" - -msgid "IDE" -msgstr "IDE" - -msgid "ATAPI" -msgstr "ATAPI" - msgid "CD-ROM %1 (%2): %3" msgstr "CD-ROM %1 (%2): %3" @@ -1688,14 +1649,14 @@ msgstr "Інструмент для планшета" msgid "About &Qt" msgstr "Про &Qt" -msgid "&MCA devices..." -msgstr "Пристрої &MCA..." +msgid "&MCA devices…" +msgstr "Пристрої &MCA…" msgid "Show non-&primary monitors" msgstr "Показати неосновні монітори" -msgid "Open screenshots &folder..." -msgstr "Відкрийте папку скріншотів..." +msgid "Open screenshots &folder…" +msgstr "Відкрийте папку скріншотів…" msgid "Appl&y fullscreen stretch mode when maximized" msgstr "Застосовувати розстягування у повноекранному режимі у максимізованому стані" @@ -1715,8 +1676,8 @@ msgstr "&Підключено" msgid "Clear image &history" msgstr "Очистити історію образів" -msgid "Create..." -msgstr "Створити..." +msgid "Create…" +msgstr "Створити…" msgid "Host CD/DVD Drive (%1)" msgstr "CD/DVD привід хоста (%1)" @@ -1757,8 +1718,8 @@ msgstr "Шейдери" msgid "Remove" msgstr "Видалити" -msgid "Browse..." -msgstr "Огляд..." +msgid "Browse…" +msgstr "Огляд…" msgid "Couldn't create OpenGL context." msgstr "Не вдалося створити контекст OpenGL." @@ -1847,8 +1808,8 @@ msgstr "Пропуск послідовного порту 3" msgid "Serial port passthrough 4" msgstr "Пропуск послідовного порту 4" -msgid "Renderer &options..." -msgstr "Параметри рендерингу..." +msgid "Renderer &options…" +msgstr "Параметри рендерингу…" msgid "PC/XT Keyboard" msgstr "Клавіатура PC/XT" @@ -1901,8 +1862,8 @@ msgstr "3M MicroTouch (послідовна)" msgid "Default Baud rate" msgstr "Швидкість передачі даних за замовчуванням" -msgid "[COM] Standard Hayes-compliant Modem" -msgstr "[COM] Стандартний модем, сумісний зі стандартом Hayes" +msgid "Standard Hayes-compliant Modem" +msgstr "Стандартний модем, сумісний зі стандартом Hayes" msgid "Roland MT-32 Emulation" msgstr "Емуляція Roland MT-32" @@ -1985,6 +1946,9 @@ msgstr "IRQ послідовного порту" msgid "Parallel port IRQ" msgstr "IRQ паралельного порту" +msgid "Hard disk" +msgstr "Жорсткий диск" + msgid "BIOS Revision" msgstr "Ревізія BIOS" @@ -2060,9 +2024,6 @@ msgstr "Прохід MIDI-вхіду" msgid "MIDI Clockout" msgstr "Вихід MIDI-годинника" -msgid "SoundFont" -msgstr "SoundFont" - msgid "Output Gain" msgstr "Вихідний коефіцієнт підсилення" @@ -2855,9 +2816,6 @@ msgstr "Переключити повноекранний режим" msgid "Toggle UI in fullscreen" msgstr "Переключити UI в повноекранному режимі" -msgid "Screenshot" -msgstr "Скріншот" - msgid "Release mouse pointer" msgstr "Відпустити вказівник миші" @@ -2972,8 +2930,8 @@ msgstr "Відкрити сторінку завантаження" msgid "Update check" msgstr "Перевірка оновлень" -msgid "Checking for updates..." -msgstr "Перевірка оновлень..." +msgid "Checking for updates…" +msgstr "Перевірка оновлень…" msgid "86Box Update" msgstr "Оновлення 86Box" @@ -3011,8 +2969,8 @@ msgstr "Яскравість" msgid "Sharpness" msgstr "Гострота" -msgid "&CGA composite settings..." -msgstr "Налаштування композитного відео &CGA..." +msgid "&CGA composite settings…" +msgstr "Налаштування композитного відео &CGA…" msgid "CGA composite settings" msgstr "Налаштування композитного відео CGA" @@ -3020,8 +2978,8 @@ msgstr "Налаштування композитного відео CGA" msgid "Monitor EDID" msgstr "EDID монітора" -msgid "Export..." -msgstr "Експорт..." +msgid "Export…" +msgstr "Експорт…" msgid "Export EDID" msgstr "Експорт EDID" @@ -3046,3 +3004,24 @@ msgstr "Темний" msgid "Search:" msgstr "Пошук:" + +msgid "Force interpretation" +msgstr "Примусове тлумачення" + +msgid "Allow recompilation" +msgstr "Дозволити рекомпіляцію" + +msgid "&Force interpretation" +msgstr "&Примусове тлумачення" + +msgid "&Allow recompilation" +msgstr "&Дозволити рекомпіляцію" + +msgid "&Fast forward" +msgstr "" + +msgid "Fast forward" +msgstr "" + +msgid "To change the system directory, stop all running machines." +msgstr "" diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index 09d5defa3d3..b2c7491a105 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -66,8 +66,8 @@ msgstr "Open&GL (3.0 Core)" msgid "&VNC" msgstr "&VNC" -msgid "Specify &dimensions..." -msgstr "Tự nhập độ &phân giải..." +msgid "Specify &dimensions…" +msgstr "Tự nhập độ &phân giải…" msgid "Force &4:3 display ratio" msgstr "Giữ nguyên khung hình &4:3" @@ -192,11 +192,11 @@ msgstr "&Phương tiện" msgid "&Tools" msgstr "&Công cụ" -msgid "&Settings..." -msgstr "&Cài đặt..." +msgid "&Settings…" +msgstr "&Cài đặt…" -msgid "Settings..." -msgstr "Cài đặt..." +msgid "Settings…" +msgstr "Cài đặt…" msgid "&Update status bar icons" msgstr "Cậ&p nhật biểu tượng thanh trạng thái" @@ -204,17 +204,38 @@ msgstr "Cậ&p nhật biểu tượng thanh trạng thái" msgid "Take s&creenshot" msgstr "Chụp &màn hình" +msgid "Take screenshot" +msgstr "Chụp màn hình" + +msgid "Take &raw screenshot" +msgstr "Chụp màn hình &thô" + +msgid "Take raw screenshot" +msgstr "Chụp màn hình thô" + +msgid "C&opy screenshot" +msgstr "S&ao chép ảnh chụp màn hình" + +msgid "Copy screenshot" +msgstr "Sao chép ảnh chụp màn hình" + +msgid "Copy r&aw screenshot" +msgstr "Sao chép ảnh chụp màn hình t&hô" + +msgid "Copy raw screenshot" +msgstr "Sao chép ảnh chụp màn hình thô" + msgid "S&ound" msgstr "&Âm thanh" -msgid "&Preferences..." -msgstr "&Tùy biến..." +msgid "&Preferences…" +msgstr "&Tùy biến…" msgid "Enable &Discord integration" msgstr "Bật trình trạng thái cho Discord" -msgid "Sound &gain..." -msgstr "Bộ &tăng âm..." +msgid "Sound &gain…" +msgstr "Bộ &tăng âm…" msgid "Begin trace" msgstr "Bắt đầu dò" @@ -225,20 +246,20 @@ msgstr "Ngưng dò" msgid "&Help" msgstr "&Trợ giúp" -msgid "&Documentation..." -msgstr "&Trợ giúp..." +msgid "&Documentation…" +msgstr "&Trợ giúp…" -msgid "&About 86Box..." -msgstr "&Về 86Box..." +msgid "&About 86Box…" +msgstr "&Về 86Box…" -msgid "&New image..." -msgstr "Tạo file ảnh đĩa mới..." +msgid "&New image…" +msgstr "Tạo file ảnh đĩa mới…" -msgid "&Existing image..." -msgstr "Ảnh đĩa có sẵn..." +msgid "&Existing image…" +msgstr "Ảnh đĩa có sẵn…" -msgid "Existing image (&Write-protected)..." -msgstr "Ảnh đĩa có sẵn (chống ghi đè)..." +msgid "Existing image (&Write-protected)…" +msgstr "Ảnh đĩa có sẵn (chống ghi đè)…" msgid "&Record" msgstr "&Ghi lại" @@ -255,11 +276,11 @@ msgstr "T&iến về cuối" msgid "E&ject" msgstr "Đẩy đĩ&a ra" -msgid "&Image..." -msgstr "&Ảnh đĩa..." +msgid "&Image…" +msgstr "&Ảnh đĩa…" -msgid "E&xport to 86F..." -msgstr "Xuất ra f&ile 86F..." +msgid "E&xport to 86F…" +msgstr "Xuất ra f&ile 86F…" msgid "&Mute" msgstr "Tắt tiến&g" @@ -270,8 +291,8 @@ msgstr "Làm trố&ng đĩa" msgid "Reload previous image" msgstr "Load đĩa trước đó" -msgid "&Folder..." -msgstr "Thư mụ&c..." +msgid "&Folder…" +msgstr "Thư mụ&c…" msgid "Preferences" msgstr "Tùy biến" @@ -417,17 +438,17 @@ msgstr "Cần điều khiển:" msgid "Joystick" msgstr "Cần điều khiển" -msgid "Joystick 1..." -msgstr "Cần điều khiển 1..." +msgid "Joystick 1…" +msgstr "Cần điều khiển 1…" -msgid "Joystick 2..." -msgstr "Cần điều khiển 2..." +msgid "Joystick 2…" +msgstr "Cần điều khiển 2…" -msgid "Joystick 3..." -msgstr "Cần điều khiển 3..." +msgid "Joystick 3…" +msgstr "Cần điều khiển 3…" -msgid "Joystick 4..." -msgstr "Cần điều khiển 4..." +msgid "Joystick 4…" +msgstr "Cần điều khiển 4…" msgid "Sound card #1:" msgstr "Card âm thanh 1:" @@ -516,10 +537,10 @@ msgstr "Cổng parallel 3" msgid "Parallel port 4" msgstr "Cổng parallel 4" -msgid "FD Controller:" +msgid "Floppy disk controller:" msgstr "Bộ điều khiển ổ mềm:" -msgid "CD-ROM Controller:" +msgid "CD-ROM controller:" msgstr "Bộ điều khiển CD-ROM:" msgid "Tertiary IDE Controller" @@ -528,11 +549,11 @@ msgstr "Bộ điều khiển IDE thứ ba" msgid "Quaternary IDE Controller" msgstr "Bộ điều khiển IDE thứ tư" -msgid "Hard disk" -msgstr "Ổ cứng" +msgid "Hard disk controllers" +msgstr "Bộ điều khiển ổ cứng" -msgid "SCSI" -msgstr "SCSI" +msgid "SCSI controllers" +msgstr "Bộ điều khiển SCSI" msgid "Controller 1:" msgstr "Bộ điều khiển 1:" @@ -555,11 +576,11 @@ msgstr "Đĩa cứng:" msgid "Firmware Version" msgstr "Phiên bản firmware" -msgid "&New..." -msgstr "Tạ&o mới..." +msgid "&New…" +msgstr "Tạ&o mới…" -msgid "&Existing..." -msgstr "&Có sẵn..." +msgid "&Existing…" +msgstr "&Có sẵn…" msgid "&Remove" msgstr "Loạ&i bỏ" @@ -867,9 +888,6 @@ msgstr "Tay cầm game bốn nút" msgid "6-button gamepad" msgstr "Tay cầm game sáu nút" -msgid "Gravis PC GamePad" -msgstr "Gravis PC GamePad" - msgid "2-button flight yoke" msgstr "Vô lăng máy bay hai nút" @@ -897,51 +915,6 @@ msgstr "Vô lăng (ba trục, ba nút)" msgid "Steering wheel (3-axis, 4-button)" msgstr "Vô lăng (ba trục, bốn nút)" -msgid "CH Flightstick" -msgstr "CH Flightstick" - -msgid "CH Flightstick + CH Pedals" -msgstr "CH Flightstick + bàn giậm CH" - -msgid "CH Flightstick + CH Pedals Pro" -msgstr "CH Flightstick + bàn giậm CH Pro" - -msgid "CH Flightstick Pro" -msgstr "CH Flightstick Pro" - -msgid "CH Flightstick Pro + CH Pedals" -msgstr "CH Flightstick Pro + bàn giậm CH" - -msgid "CH Flightstick Pro + CH Pedals Pro" -msgstr "CH Flightstick Pro + bàn giậm CH Pro" - -msgid "CH Virtual Pilot" -msgstr "CH Virtual Pilot" - -msgid "CH Virtual Pilot + CH Pedals" -msgstr "CH Virtual Pilot + bàn giậm CH" - -msgid "CH Virtual Pilot + CH Pedals Pro" -msgstr "CH Virtual Pilot + bàn giậm CH Pro" - -msgid "CH Virtual Pilot Pro" -msgstr "CH Virtual Pilot Pro" - -msgid "CH Virtual Pilot Pro + CH Pedals" -msgstr "CH Virtual Pilot Pro + bàn giậm CH" - -msgid "CH Virtual Pilot Pro + CH Pedals Pro" -msgstr "CH Virtual Pilot Pro + bàn giậm CH Pro" - -msgid "Microsoft SideWinder Pad" -msgstr "Microsoft SideWinder Pad" - -msgid "Thrustmaster Flight Control System" -msgstr "Thrustmaster Flight Control System" - -msgid "Thrustmaster FCS + Rudder Control System" -msgstr "Thrustmaster FCS + Hệ thống bánh lái" - msgid "Thrustmaster Formula T1/T2 with adapter" msgstr "Thrustmaster Formula T1/T2 kèm bộ chuyển đổi" @@ -996,11 +969,17 @@ msgstr "Thiết bị nội bộ" msgid "&File" msgstr "&Tập tin" -msgid "&New machine..." -msgstr "Máy &mới..." +msgid "&New machine…" +msgstr "Máy &mới…" + +msgid "New machine…" +msgstr "Máy mới…" -msgid "&Check for updates..." -msgstr "Kiểm tra &cập nhật..." +msgid "New machine" +msgstr "Máy mới" + +msgid "&Check for updates…" +msgstr "Kiểm tra &cập nhật…" msgid "Exit" msgstr "Thoát" @@ -1170,8 +1149,8 @@ msgstr "Không thể mở cấu hình đã chọn để đọc: %1" msgid "Use regular expressions in search box" msgstr "Dùng regex trong hộp tìm kiếm" -msgid "%1 machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" -msgstr "%1 máy hiện vẫn đang chạy. Bạn có muốn thoát trình quản lý máy ảo không?" +msgid "%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" +msgstr "%n máy hiện vẫn đang chạy. Bạn có muốn thoát trình quản lý máy ảo không?" msgid "Add new system wizard" msgstr "Thêm trình thuật sĩ hệ thống mới" @@ -1251,26 +1230,23 @@ msgstr "Đặt tên hiển thị" msgid "Enter the new display name (blank to reset)" msgstr "Điền tên hiển thị mới (để trống để đặt lại)" -msgid "Change &display name..." -msgstr "Thay đổi tên hiển thị..." - -msgid "Context Menu" -msgstr "Menu ngữ cảnh" +msgid "Change &display name…" +msgstr "Thay đổi tên hiển thị…" -msgid "&Open folder..." -msgstr "Mở thư mục..." +msgid "&Open folder…" +msgstr "Mở thư mục…" -msgid "Open p&rinter tray..." -msgstr "Mở khay máy in..." +msgid "Open p&rinter tray…" +msgstr "Mở khay máy in…" -msgid "Set &icon..." -msgstr "Đặt biểu trưng..." +msgid "Set &icon…" +msgstr "Đặt biểu trưng…" msgid "Select an icon" msgstr "Chọn một biểu trưng" -msgid "C&lone..." -msgstr "Tạo bản sao..." +msgid "C&lone…" +msgstr "Tạo bản sao…" msgid "Virtual machine \"%1\" (%2) will be cloned into:" msgstr "Máy ảo \"%1\" (%2) sẽ được sao chép vào:" @@ -1356,8 +1332,8 @@ msgstr "Không có ảnh chụp màn hình" msgid "Search" msgstr "Tìm" -msgid "Searching for VMs..." -msgstr "Đang tìm máy ảo..." +msgid "Searching for VMs…" +msgstr "Đang tìm máy ảo…" msgid "Found %1" msgstr "Đã thấy %1" @@ -1392,11 +1368,11 @@ msgstr "Ổ cứng (%1)" msgid "MFM/RLL or ESDI CD-ROM drives never existed" msgstr "Không hề có ổ CD-ROM MFM/RLL hay ESDI nào tồn tại" -msgid "Custom..." -msgstr "Tùy chỉnh..." +msgid "Custom…" +msgstr "Tùy chỉnh…" -msgid "Custom (large)..." -msgstr "Tùy chỉnh (dung tích lớn)..." +msgid "Custom (large)…" +msgstr "Tùy chỉnh (dung tích lớn)…" msgid "Add New Hard Disk" msgstr "Thêm ổ cứng mới" @@ -1515,21 +1491,6 @@ msgstr "Mốc timestamp của đĩa con (child) và đĩa cha (parent) không tr msgid "Could not fix VHD timestamp." msgstr "Không thể sửa mốc timestamp cho VHD." -msgid "MFM/RLL" -msgstr "MFM/RLL" - -msgid "XTA" -msgstr "XTA" - -msgid "ESDI" -msgstr "ESDI" - -msgid "IDE" -msgstr "IDE" - -msgid "ATAPI" -msgstr "ATAPI" - msgid "CD-ROM %1 (%2): %3" msgstr "CD-ROM %1 (%2): %3" @@ -1680,14 +1641,14 @@ msgstr "Công cụ bảng nhập liệu" msgid "About &Qt" msgstr "Về &qt" -msgid "&MCA devices..." -msgstr "Thiết bị MCA..." +msgid "&MCA devices…" +msgstr "Thiết bị MCA…" msgid "Show non-&primary monitors" msgstr "Hiển thị các màn hình phụ" -msgid "Open screenshots &folder..." -msgstr "Mở thư mục ảnh chụp màn hình..." +msgid "Open screenshots &folder…" +msgstr "Mở thư mục ảnh chụp màn hình…" msgid "Appl&y fullscreen stretch mode when maximized" msgstr "Co giãn toàn màn hình khi cực đại hóa cửa sổ" @@ -1707,8 +1668,8 @@ msgstr "&Đã kết nối" msgid "Clear image &history" msgstr "Xóa lịch sử ảnh đĩa" -msgid "Create..." -msgstr "Tạo..." +msgid "Create…" +msgstr "Tạo…" msgid "Host CD/DVD Drive (%1)" msgstr "Máy chủ CD/DVD Drive (%1)" @@ -1749,8 +1710,8 @@ msgstr "Shaders" msgid "Remove" msgstr "Loại bỏ" -msgid "Browse..." -msgstr "Duyệt..." +msgid "Browse…" +msgstr "Duyệt…" msgid "Couldn't create OpenGL context." msgstr "Không thể tạo bối cảnh OpenGL." @@ -1839,8 +1800,8 @@ msgstr "Thông qua cổng serial 3" msgid "Serial port passthrough 4" msgstr "Thông qua cổng serial 4" -msgid "Renderer &options..." -msgstr "Tùy chọn kết xuất ..." +msgid "Renderer &options…" +msgstr "Tùy chọn kết xuất…" msgid "PC/XT Keyboard" msgstr "Bàn phím PC/XT" @@ -1893,8 +1854,8 @@ msgstr "3M MicroTouch (Serial)" msgid "Default Baud rate" msgstr "Tốc độ baud mặc định" -msgid "[COM] Standard Hayes-compliant Modem" -msgstr "[COM] Modem tuân thủ tiêu chuẩn Hayes" +msgid "Standard Hayes-compliant Modem" +msgstr "Modem tuân thủ tiêu chuẩn Hayes" msgid "Roland MT-32 Emulation" msgstr "Mô phỏng Roland MT-32" @@ -1977,6 +1938,9 @@ msgstr "IRQ cổng serial" msgid "Parallel port IRQ" msgstr "IRQ cổng parallel" +msgid "Hard disk" +msgstr "Ổ cứng" + msgid "BIOS Revision" msgstr "Sửa đổi BIOS" @@ -2052,9 +2016,6 @@ msgstr "Thông qua đầu vào MIDI" msgid "MIDI Clockout" msgstr "MIDI Clockout" -msgid "SoundFont" -msgstr "Font âm thanh" - msgid "Output Gain" msgstr "Tăng đầu ra" @@ -2847,9 +2808,6 @@ msgstr "Bật/tắt toàn màn hình" msgid "Toggle UI in fullscreen" msgstr "" -msgid "Screenshot" -msgstr "Chụp màn hình" - msgid "Release mouse pointer" msgstr "Thả con trỏ chuột" @@ -2964,8 +2922,8 @@ msgstr "Truy cập trang tải xuống" msgid "Update check" msgstr "Kiểm tra cập nhật" -msgid "Checking for updates..." -msgstr "Đang kiểm tra cập nhật..." +msgid "Checking for updates…" +msgstr "Đang kiểm tra cập nhật…" msgid "86Box Update" msgstr "Cập nhật 86Box" @@ -3003,8 +2961,8 @@ msgstr "Độ sáng" msgid "Sharpness" msgstr "Độ sắc nét" -msgid "&CGA composite settings..." -msgstr "Cài đặt chế độ tổng hợp &CGA..." +msgid "&CGA composite settings…" +msgstr "Cài đặt chế độ tổng hợp &CGA…" msgid "CGA composite settings" msgstr "Cài đặt chế độ tổng hợp CGA" @@ -3012,8 +2970,8 @@ msgstr "Cài đặt chế độ tổng hợp CGA" msgid "Monitor EDID" msgstr "EDID của màn hình" -msgid "Export..." -msgstr "Xuất khẩu..." +msgid "Export…" +msgstr "Xuất khẩu…" msgid "Export EDID" msgstr "Xuất khẩu EDID" @@ -3038,3 +2996,24 @@ msgstr "Tối" msgid "Search:" msgstr "Tìm:" + +msgid "Force interpretation" +msgstr "Buộc giải thích" + +msgid "Allow recompilation" +msgstr "Cho phép biên dịch lại" + +msgid "&Force interpretation" +msgstr "&Buộc giải thích" + +msgid "&Allow recompilation" +msgstr "&Cho phép biên dịch lại" + +msgid "&Fast forward" +msgstr "" + +msgid "Fast forward" +msgstr "" + +msgid "To change the system directory, stop all running machines." +msgstr "" diff --git a/src/qt/languages/zh-CN.po b/src/qt/languages/zh-CN.po index 96951cdd75b..a960d8b2d35 100644 --- a/src/qt/languages/zh-CN.po +++ b/src/qt/languages/zh-CN.po @@ -1,8 +1,15 @@ msgid "" msgstr "" +"PO-Revision-Date: 2026-01-18 19:18+0000\n" +"Last-Translator: BlueRain-debug \n" +"Language-Team: Chinese (Simplified Han script) \n" +"Language: zh-CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 5.12.2\n" "X-Language: zh_CN\n" "X-Source-Language: en_US\n" @@ -66,8 +73,8 @@ msgstr "OpenGL (3.0 Core)(&G)" msgid "&VNC" msgstr "VNC(&V)" -msgid "Specify &dimensions..." -msgstr "指定窗口大小(&D)..." +msgid "Specify &dimensions…" +msgstr "指定窗口大小(&D)…" msgid "Force &4:3 display ratio" msgstr "强制 4:3 显示比例(&4)" @@ -192,11 +199,11 @@ msgstr "介质(&M)" msgid "&Tools" msgstr "工具(&T)" -msgid "&Settings..." -msgstr "设置(&S)..." +msgid "&Settings…" +msgstr "设置(&S)…" -msgid "Settings..." -msgstr "设置..." +msgid "Settings…" +msgstr "设置…" msgid "&Update status bar icons" msgstr "更新状态栏图标(&U)" @@ -204,17 +211,38 @@ msgstr "更新状态栏图标(&U)" msgid "Take s&creenshot" msgstr "截图(&C)" +msgid "Take screenshot" +msgstr "截图" + +msgid "Take &raw screenshot" +msgstr "原始截图(&R)" + +msgid "Take raw screenshot" +msgstr "原始截图" + +msgid "C&opy screenshot" +msgstr "复制截图(&O)" + +msgid "Copy screenshot" +msgstr "复制截图" + +msgid "Copy r&aw screenshot" +msgstr "复制原始截图(&A)" + +msgid "Copy raw screenshot" +msgstr "复制原始截图" + msgid "S&ound" msgstr "声音(&O)" -msgid "&Preferences..." -msgstr "首选项(&P)..." +msgid "&Preferences…" +msgstr "首选项(&P)…" msgid "Enable &Discord integration" msgstr "启用 Discord 集成(&D)" -msgid "Sound &gain..." -msgstr "音量增益(&G)..." +msgid "Sound &gain…" +msgstr "音量增益(&G)…" msgid "Begin trace" msgstr "开始追踪" @@ -225,20 +253,20 @@ msgstr "结束追踪" msgid "&Help" msgstr "帮助(&H)" -msgid "&Documentation..." -msgstr "文档(&D)..." +msgid "&Documentation…" +msgstr "文档(&D)…" -msgid "&About 86Box..." -msgstr "关于 86Box(&A)..." +msgid "&About 86Box…" +msgstr "关于 86Box(&A)…" -msgid "&New image..." -msgstr "新建映像(&N)..." +msgid "&New image…" +msgstr "新建映像(&N)…" -msgid "&Existing image..." -msgstr "打开已存在的映像(&E)..." +msgid "&Existing image…" +msgstr "打开已存在的映像(&E)…" -msgid "Existing image (&Write-protected)..." -msgstr "打开已存在的映像并写保护(&W)..." +msgid "Existing image (&Write-protected)…" +msgstr "打开已存在的映像并写保护(&W)…" msgid "&Record" msgstr "录制(&R)" @@ -255,11 +283,11 @@ msgstr "快进至终点(&F)" msgid "E&ject" msgstr "弹出(&J)" -msgid "&Image..." -msgstr "映像(&I)..." +msgid "&Image…" +msgstr "映像(&I)…" -msgid "E&xport to 86F..." -msgstr "导出为 86F 格式(&x)..." +msgid "E&xport to 86F…" +msgstr "导出为 86F 格式(&x)…" msgid "&Mute" msgstr "静音(&M)" @@ -270,8 +298,8 @@ msgstr "空置驱动器(&M)" msgid "Reload previous image" msgstr "载入上一个映像" -msgid "&Folder..." -msgstr "文件夹(&F)..." +msgid "&Folder…" +msgstr "文件夹(&F)…" msgid "Preferences" msgstr "首选项" @@ -417,17 +445,17 @@ msgstr "操纵杆:" msgid "Joystick" msgstr "操纵杆" -msgid "Joystick 1..." -msgstr "操纵杆 1..." +msgid "Joystick 1…" +msgstr "操纵杆 1…" -msgid "Joystick 2..." -msgstr "操纵杆 2..." +msgid "Joystick 2…" +msgstr "操纵杆 2…" -msgid "Joystick 3..." -msgstr "操纵杆 3..." +msgid "Joystick 3…" +msgstr "操纵杆 3…" -msgid "Joystick 4..." -msgstr "操纵杆 4..." +msgid "Joystick 4…" +msgstr "操纵杆 4…" msgid "Sound card #1:" msgstr "声卡 1:" @@ -516,10 +544,10 @@ msgstr "并口 3" msgid "Parallel port 4" msgstr "并口 4" -msgid "FD Controller:" +msgid "Floppy disk controller:" msgstr "软盘控制器:" -msgid "CD-ROM Controller:" +msgid "CD-ROM controller:" msgstr "CD-ROM 控制器:" msgid "Tertiary IDE Controller" @@ -528,11 +556,11 @@ msgstr "第三 IDE 控制器" msgid "Quaternary IDE Controller" msgstr "第四 IDE 控制器" -msgid "Hard disk" -msgstr "硬盘" +msgid "Hard disk controllers" +msgstr "硬盘控制器" -msgid "SCSI" -msgstr "SCSI" +msgid "SCSI controllers" +msgstr "SCSI 控制器" msgid "Controller 1:" msgstr "控制器 1:" @@ -555,11 +583,11 @@ msgstr "硬盘:" msgid "Firmware Version" msgstr "固件版本" -msgid "&New..." -msgstr "新建(&N)..." +msgid "&New…" +msgstr "新建(&N)…" -msgid "&Existing..." -msgstr "已有映像(&E)..." +msgid "&Existing…" +msgstr "现有(&E)…" msgid "&Remove" msgstr "移除(&R)" @@ -867,9 +895,6 @@ msgstr "4 按钮游戏手柄" msgid "6-button gamepad" msgstr "6 按钮游戏手柄" -msgid "Gravis PC GamePad" -msgstr "Gravis PC GamePad" - msgid "2-button flight yoke" msgstr "2 按钮飞行摇杆" @@ -897,56 +922,11 @@ msgstr "方向盘 (3 轴, 3 键)" msgid "Steering wheel (3-axis, 4-button)" msgstr "方向盘 (3 轴, 4 键)" -msgid "CH Flightstick" -msgstr "CH Flightstick" - -msgid "CH Flightstick + CH Pedals" -msgstr "CH Flightstick + CH Pedals" - -msgid "CH Flightstick + CH Pedals Pro" -msgstr "CH Flightstick + CH Pedals Pro" - -msgid "CH Flightstick Pro" -msgstr "CH Flightstick Pro" - -msgid "CH Flightstick Pro + CH Pedals" -msgstr "CH Flightstick Pro + CH Pedals" - -msgid "CH Flightstick Pro + CH Pedals Pro" -msgstr "CH Flightstick Pro + CH Pedals Pro" - -msgid "CH Virtual Pilot" -msgstr "CH Virtual Pilot" - -msgid "CH Virtual Pilot + CH Pedals" -msgstr "CH Virtual Pilot + CH Pedals" - -msgid "CH Virtual Pilot + CH Pedals Pro" -msgstr "CH Virtual Pilot + CH Pedals Pro" - -msgid "CH Virtual Pilot Pro" -msgstr "CH Virtual Pilot Pro" - -msgid "CH Virtual Pilot Pro + CH Pedals" -msgstr "CH Virtual Pilot Pro + CH Pedals" - -msgid "CH Virtual Pilot Pro + CH Pedals Pro" -msgstr "CH Virtual Pilot Pro + CH Pedals Pro" - -msgid "Microsoft SideWinder Pad" -msgstr "Microsoft SideWinder Pad" - -msgid "Thrustmaster Flight Control System" -msgstr "Thrustmaster Flight Control System" - -msgid "Thrustmaster FCS + Rudder Control System" -msgstr "Thrustmaster FCS + Rudder Control System" - msgid "Thrustmaster Formula T1/T2 with adapter" -msgstr "带适配器 Thrustmaster Formula T1/T2" +msgstr "带适配器的 Thrustmaster Formula T1/T2" msgid "Thrustmaster Formula T1/T2 without adapter" -msgstr "不带适配器 Thrustmaster Formula T1/T2" +msgstr "不带适配器的 Thrustmaster Formula T1/T2" msgid "None" msgstr "无" @@ -996,11 +976,17 @@ msgstr "内部设备" msgid "&File" msgstr "文件(&F)" -msgid "&New machine..." -msgstr "新建计算机(&N)..." +msgid "&New machine…" +msgstr "新建计算机(&N)…" + +msgid "New machine…" +msgstr "新建计算机…" -msgid "&Check for updates..." -msgstr "检查更新(&C)..." +msgid "New machine" +msgstr "新建计算机" + +msgid "&Check for updates…" +msgstr "检查更新(&C)…" msgid "Exit" msgstr "退出" @@ -1170,8 +1156,8 @@ msgstr "无法打开选定的配置文件进行读取:%1" msgid "Use regular expressions in search box" msgstr "在搜索框中使用正则表达式" -msgid "%1 machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" -msgstr "%1 个计算机当前处于活动状态。您确定要退出虚拟机管理器吗?" +msgid "%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" +msgstr "%n 个计算机当前处于活动状态。您确定要退出虚拟机管理器吗?" msgid "Add new system wizard" msgstr "添加新系统向导" @@ -1251,26 +1237,23 @@ msgstr "设置显示名称" msgid "Enter the new display name (blank to reset)" msgstr "输入新的显示名称 (留空以重置)" -msgid "Change &display name..." -msgstr "更改显示名称(&D)..." - -msgid "Context Menu" -msgstr "上下文菜单" +msgid "Change &display name…" +msgstr "更改显示名称(&D)…" -msgid "&Open folder..." -msgstr "打开文件夹(&O)..." +msgid "&Open folder…" +msgstr "打开文件夹(&O)…" -msgid "Open p&rinter tray..." -msgstr "打开打印机托盘(&R)..." +msgid "Open p&rinter tray…" +msgstr "打开打印机托盘(&R)…" -msgid "Set &icon..." -msgstr "设置图标(&I)..." +msgid "Set &icon…" +msgstr "设置图标(&I)…" msgid "Select an icon" msgstr "选择一个图标" -msgid "C&lone..." -msgstr "克隆(&L)..." +msgid "C&lone…" +msgstr "克隆(&L)…" msgid "Virtual machine \"%1\" (%2) will be cloned into:" msgstr "虚拟机 \"%1\" (%2) 将被克隆到:" @@ -1356,8 +1339,8 @@ msgstr "无截图" msgid "Search" msgstr "搜索" -msgid "Searching for VMs..." -msgstr "正在搜索虚拟机..." +msgid "Searching for VMs…" +msgstr "正在搜索虚拟机…" msgid "Found %1" msgstr "已找到 %1" @@ -1384,7 +1367,7 @@ msgid "ACPI shutdown" msgstr "ACPI 关机" msgid "ACP&I shutdown" -msgstr "ACP&I 关机" +msgstr "ACPI 关机(&I)" msgid "Hard disk (%1)" msgstr "硬盘 (%1)" @@ -1392,11 +1375,11 @@ msgstr "硬盘 (%1)" msgid "MFM/RLL or ESDI CD-ROM drives never existed" msgstr "不存在 MFM/RLL 或 ESDI CD-ROM 驱动器" -msgid "Custom..." -msgstr "自定义..." +msgid "Custom…" +msgstr "自定义…" -msgid "Custom (large)..." -msgstr "自定义 (大容量)..." +msgid "Custom (large)…" +msgstr "自定义 (大容量)…" msgid "Add New Hard Disk" msgstr "添加新硬盘" @@ -1515,21 +1498,6 @@ msgstr "父盘与子盘的时间戳不匹配" msgid "Could not fix VHD timestamp." msgstr "无法修复 VHD 时间戳。" -msgid "MFM/RLL" -msgstr "MFM/RLL" - -msgid "XTA" -msgstr "XTA" - -msgid "ESDI" -msgstr "ESDI" - -msgid "IDE" -msgstr "IDE" - -msgid "ATAPI" -msgstr "ATAPI" - msgid "CD-ROM %1 (%2): %3" msgstr "光盘 %1 (%2): %3" @@ -1680,14 +1648,14 @@ msgstr "平板工具(&T)" msgid "About &Qt" msgstr "关于 &Qt" -msgid "&MCA devices..." -msgstr "&MCA 设备..." +msgid "&MCA devices…" +msgstr "&MCA 设备…" msgid "Show non-&primary monitors" msgstr "显示非主要显示器(&P)" -msgid "Open screenshots &folder..." -msgstr "打开屏幕截图文件夹(&F)..." +msgid "Open screenshots &folder…" +msgstr "打开屏幕截图文件夹(&F)…" msgid "Appl&y fullscreen stretch mode when maximized" msgstr "最大化时应用全屏拉伸模式(&Y)" @@ -1705,10 +1673,10 @@ msgid "&Connected" msgstr "已连接(&C)" msgid "Clear image &history" -msgstr "清除映像历史记录(&H)" +msgstr "清除镜像文件历史记录(&H)" -msgid "Create..." -msgstr "创建..." +msgid "Create…" +msgstr "创建…" msgid "Host CD/DVD Drive (%1)" msgstr "主机 CD/DVD 驱动器 (%1)" @@ -1749,8 +1717,8 @@ msgstr "着色器" msgid "Remove" msgstr "移除" -msgid "Browse..." -msgstr "浏览..." +msgid "Browse…" +msgstr "浏览…" msgid "Couldn't create OpenGL context." msgstr "无法创建 OpenGL 上下文。" @@ -1768,7 +1736,7 @@ msgid "\nFalling back to software rendering." msgstr "\n回到软件渲染。" msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" -msgstr "

选择媒体图像(光盘、软盘等)时,打开对话框将从与 86Box 配置文件相同的目录开始。这一设置可能只会在 macOS 上产生影响。

" +msgstr "

选择媒体镜像(光盘、软盘等)时,打开对话框将从与 86Box 配置文件相同的目录开始。这一设置可能只会在 macOS 上产生影响。

" msgid "This machine might have been moved or copied." msgstr "这台机器可能被移动或复制过。" @@ -1810,7 +1778,7 @@ msgid "Mode:" msgstr "模式:" msgid "Interface:" -msgstr "界面:" +msgstr "接口:" msgid "Adapter:" msgstr "适配器:" @@ -1839,8 +1807,8 @@ msgstr "串口直通 3" msgid "Serial port passthrough 4" msgstr "串口直通 4" -msgid "Renderer &options..." -msgstr "渲染器选项(&O)..." +msgid "Renderer &options…" +msgstr "渲染器选项(&O)…" msgid "PC/XT Keyboard" msgstr "PC/XT 键盘" @@ -1893,8 +1861,8 @@ msgstr "3M MicroTouch (串口)" msgid "Default Baud rate" msgstr "默认波特率" -msgid "[COM] Standard Hayes-compliant Modem" -msgstr "[COM] 标准 Hayes 兼容调制解调器" +msgid "Standard Hayes-compliant Modem" +msgstr "标准 Hayes 兼容调制解调器" msgid "Roland MT-32 Emulation" msgstr "Roland MT-32 仿真" @@ -1977,6 +1945,9 @@ msgstr "串口的 IRQ" msgid "Parallel port IRQ" msgstr "并口的 IRQ" +msgid "Hard disk" +msgstr "硬盘" + msgid "BIOS Revision" msgstr "BIOS 修订版" @@ -2052,9 +2023,6 @@ msgstr "MIDI 输入直通" msgid "MIDI Clockout" msgstr "MIDI 时钟输出" -msgid "SoundFont" -msgstr "声音字体" - msgid "Output Gain" msgstr "输出增益" @@ -2617,7 +2585,7 @@ msgid "3Dfx Voodoo 2" msgstr "3Dfx Voodoo 2" msgid "Obsidian SB50 + Amethyst (2 TMUs)" -msgstr "Obsidian SB50 + Amethyst(2 个 TMU)" +msgstr "Obsidian SB50 + Amethyst(双TMU)" msgid "8-bit" msgstr "8 位" @@ -2847,9 +2815,6 @@ msgstr "切换全屏" msgid "Toggle UI in fullscreen" msgstr "在全屏模式下激活菜单栏" -msgid "Screenshot" -msgstr "截图" - msgid "Release mouse pointer" msgstr "释放鼠标" @@ -2964,14 +2929,14 @@ msgstr "访问下载页面" msgid "Update check" msgstr "更新检查" -msgid "Checking for updates..." -msgstr "正在检查更新..." +msgid "Checking for updates…" +msgstr "正在检查更新…" msgid "86Box Update" msgstr "86Box 更新" msgid "Release notes:" -msgstr "发行版说明:" +msgstr "发行说明:" msgid "%1 Hz" msgstr "%1 Hz" @@ -3003,8 +2968,8 @@ msgstr "亮度" msgid "Sharpness" msgstr "锐度" -msgid "&CGA composite settings..." -msgstr "CGA 复合模式设置(&C)..." +msgid "&CGA composite settings…" +msgstr "CGA 复合模式设置(&C)…" msgid "CGA composite settings" msgstr "CGA 复合模式设置" @@ -3012,8 +2977,8 @@ msgstr "CGA 复合模式设置" msgid "Monitor EDID" msgstr "显示器的EDID" -msgid "Export..." -msgstr "导出..." +msgid "Export…" +msgstr "导出…" msgid "Export EDID" msgstr "导出EDID" @@ -3038,3 +3003,24 @@ msgstr "暗色" msgid "Search:" msgstr "搜索:" + +msgid "Force interpretation" +msgstr "强制解释执行" + +msgid "Allow recompilation" +msgstr "允许重编译" + +msgid "&Force interpretation" +msgstr "强制解释执行(&F)" + +msgid "&Allow recompilation" +msgstr "允许重编译(&A)" + +msgid "&Fast forward" +msgstr "快进(&F)" + +msgid "Fast forward" +msgstr "快进" + +msgid "To change the system directory, stop all running machines." +msgstr "请在变更系统目录前关闭所有正在运行的虚拟机。" diff --git a/src/qt/languages/zh-TW.po b/src/qt/languages/zh-TW.po index d17f369230c..0bdcd215a0f 100644 --- a/src/qt/languages/zh-TW.po +++ b/src/qt/languages/zh-TW.po @@ -1,8 +1,15 @@ msgid "" msgstr "" +"PO-Revision-Date: 2026-01-02 21:56+0000\n" +"Last-Translator: Alexander Babikov \n" +"Language-Team: Chinese (Traditional Han script) \n" +"Language: zh-TW\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 5.12.2\n" "X-Language: zh_TW\n" "X-Source-Language: en_US\n" @@ -66,8 +73,8 @@ msgstr "OpenGL (3.0 Core)(&G)" msgid "&VNC" msgstr "VNC(&V)" -msgid "Specify &dimensions..." -msgstr "指定視窗大小(&D)..." +msgid "Specify &dimensions…" +msgstr "指定視窗大小(&D)…" msgid "Force &4:3 display ratio" msgstr "強制 4:3 顯示比例(&4)" @@ -115,7 +122,7 @@ msgid "&Linear" msgstr "線性(&L)" msgid "Hi&DPI scaling" -msgstr "HiDPI 縮放(&D)" +msgstr "高 DPI 縮放(&D)" msgid "&Fullscreen" msgstr "全螢幕(&F)" @@ -192,29 +199,50 @@ msgstr "媒體(&M)" msgid "&Tools" msgstr "工具(&T)" -msgid "&Settings..." -msgstr "設定(&S)..." +msgid "&Settings…" +msgstr "設定(&S)…" -msgid "Settings..." -msgstr "設定..." +msgid "Settings…" +msgstr "設定…" msgid "&Update status bar icons" msgstr "更新狀態列圖示(&U)" msgid "Take s&creenshot" -msgstr "擷圖(&C)" +msgstr "擷取螢幕畫面(&C)" + +msgid "Take screenshot" +msgstr "擷取螢幕畫面" + +msgid "Take &raw screenshot" +msgstr "擷取原始螢幕畫面(&R)" + +msgid "Take raw screenshot" +msgstr "擷取原始螢幕畫面" + +msgid "C&opy screenshot" +msgstr "擷取螢幕畫面至剪貼簿(&O)" + +msgid "Copy screenshot" +msgstr "擷取螢幕畫面至剪貼簿" + +msgid "Copy r&aw screenshot" +msgstr "擷取原始螢幕畫面至剪貼薄(&A)" + +msgid "Copy raw screenshot" +msgstr "擷取原始螢幕畫面至剪貼薄" msgid "S&ound" msgstr "聲音(&O)" -msgid "&Preferences..." -msgstr "偏好設定(&P)..." +msgid "&Preferences…" +msgstr "偏好設定(&P)…" msgid "Enable &Discord integration" msgstr "啟用 Discord 整合(&D)" -msgid "Sound &gain..." -msgstr "音量增益(&G)..." +msgid "Sound &gain…" +msgstr "音量增益(&G)…" msgid "Begin trace" msgstr "開始追踪" @@ -225,20 +253,20 @@ msgstr "結束追踪" msgid "&Help" msgstr "說明(&H)" -msgid "&Documentation..." -msgstr "文件(&D)..." +msgid "&Documentation…" +msgstr "文件(&D)…" -msgid "&About 86Box..." -msgstr "關於 86Box(&A)..." +msgid "&About 86Box…" +msgstr "關於 86Box(&A)…" -msgid "&New image..." -msgstr "新增影像(&N)..." +msgid "&New image…" +msgstr "新增影像(&N)…" -msgid "&Existing image..." -msgstr "開啟已存在的影像(&E)..." +msgid "&Existing image…" +msgstr "開啟已存在的影像(&E)…" -msgid "Existing image (&Write-protected)..." -msgstr "以防寫保護開啟已存在的影像(&W)..." +msgid "Existing image (&Write-protected)…" +msgstr "以防寫保護開啟已存在的影像(&W)…" msgid "&Record" msgstr "錄製(&R)" @@ -247,31 +275,31 @@ msgid "&Play" msgstr "播放(&P)" msgid "&Rewind to the beginning" -msgstr "倒帶至起點(&R)" +msgstr "倒轉至起點(&R)" msgid "&Fast forward to the end" -msgstr "快進至終點(&F)" +msgstr "快轉至終點(&F)" msgid "E&ject" msgstr "退出(&J)" -msgid "&Image..." -msgstr "影像(&I)..." +msgid "&Image…" +msgstr "影像(&I)…" -msgid "E&xport to 86F..." -msgstr "匯出為 86F 格式(&x)..." +msgid "E&xport to 86F…" +msgstr "匯出為 86F 格式(&x)…" msgid "&Mute" msgstr "靜音(&M)" msgid "E&mpty" -msgstr "空置光碟機(&M)" +msgstr "卸載(&M)" msgid "Reload previous image" msgstr "載入上一個影像" -msgid "&Folder..." -msgstr "資料夾(&F)..." +msgid "&Folder…" +msgstr "資料夾(&F)…" msgid "Preferences" msgstr "偏好設定" @@ -331,7 +359,7 @@ msgid "Machine:" msgstr "機型:" msgid "Configure" -msgstr "設定" +msgstr "組態" msgid "CPU:" msgstr "CPU:" @@ -373,13 +401,13 @@ msgid "Dynamic Recompiler" msgstr "動態重編譯器" msgid "CPU frame size" -msgstr "CPU 執行幀大小" +msgstr "CPU 執行期框架大小" msgid "Larger frames (less smooth)" -msgstr "大執行幀 (操作欠平滑)" +msgstr "大執行期框架 (運行欠平順)" msgid "Smaller frames (smoother)" -msgstr "小執行幀 (操作更平滑)" +msgstr "小執行期框架 (運行更平順)" msgid "Video:" msgstr "顯示卡:" @@ -417,17 +445,17 @@ msgstr "搖桿:" msgid "Joystick" msgstr "搖桿" -msgid "Joystick 1..." -msgstr "搖桿 1..." +msgid "Joystick 1…" +msgstr "搖桿 1…" -msgid "Joystick 2..." -msgstr "搖桿 2..." +msgid "Joystick 2…" +msgstr "搖桿 2…" -msgid "Joystick 3..." -msgstr "搖桿 3..." +msgid "Joystick 3…" +msgstr "搖桿 3…" -msgid "Joystick 4..." -msgstr "搖桿 4..." +msgid "Joystick 4…" +msgstr "搖桿 4…" msgid "Sound card #1:" msgstr "音效卡 1:" @@ -516,10 +544,10 @@ msgstr "並列埠 3" msgid "Parallel port 4" msgstr "並列埠 4" -msgid "FD Controller:" +msgid "Floppy disk controller:" msgstr "軟碟控制器:" -msgid "CD-ROM Controller:" +msgid "CD-ROM controller:" msgstr "CD-ROM 控制器:" msgid "Tertiary IDE Controller" @@ -528,11 +556,11 @@ msgstr "第三 IDE 控制器" msgid "Quaternary IDE Controller" msgstr "第四 IDE 控制器" -msgid "Hard disk" -msgstr "硬碟" +msgid "Hard disk controllers" +msgstr "硬碟控制器" -msgid "SCSI" -msgstr "SCSI" +msgid "SCSI controllers" +msgstr "SCSI 控制器" msgid "Controller 1:" msgstr "控制器 1:" @@ -555,11 +583,11 @@ msgstr "硬碟:" msgid "Firmware Version" msgstr "韌體版本" -msgid "&New..." -msgstr "新增(&N)..." +msgid "&New…" +msgstr "新增(&N)…" -msgid "&Existing..." -msgstr "已有影像(&E)..." +msgid "&Existing…" +msgstr "已有影像(&E)…" msgid "&Remove" msgstr "移除(&R)" @@ -613,10 +641,10 @@ msgid "MO:" msgstr "磁光碟:" msgid "Removable disks:" -msgstr "可移除磁碟:" +msgstr "抽取式磁碟:" msgid "Removable disk drives:" -msgstr "可移除磁碟機:" +msgstr "抽取式磁碟機:" msgid "ZIP 250" msgstr "ZIP 250" @@ -643,13 +671,13 @@ msgid "Card 4:" msgstr "擴充卡 4:" msgid "Generic ISA ROM Board" -msgstr "通用 ISA ROM 板" +msgstr "通用 ISA 單 ROM 板" msgid "Generic Dual ISA ROM Board" -msgstr "通用雙 ISA ROM 板" +msgstr "通用 ISA 雙 ROM 板" msgid "Generic Quad ISA ROM Board" -msgstr "通用四通道 ISA ROM 板" +msgstr "通用 ISA 四 ROM 板" msgid "ISABugger device" msgstr "ISABugger 裝置" @@ -670,13 +698,13 @@ msgid "Speed" msgstr "速度" msgid "Removable disk %1 (%2): %3" -msgstr "可移除磁碟 %1 (%2): %3" +msgstr "抽取式磁碟 %1 (%2): %3" msgid "&Removable disk %1 (%2): %3" -msgstr "可移除磁碟(&R) %1 (%2): %3" +msgstr "抽取式磁碟(&R) %1 (%2): %3" msgid "Removable disk images" -msgstr "可移除磁碟影像" +msgstr "抽取式磁碟影像" msgid "Image %1" msgstr "影像 %1" @@ -748,7 +776,7 @@ msgid "Parallel ports:" msgstr "並列埠:" msgid "Storage controllers" -msgstr "存儲控制器" +msgstr "儲存控制器" msgid "Hard disks" msgstr "硬碟" @@ -766,7 +794,7 @@ msgid "Floppy & CD-ROM drives" msgstr "軟碟/光碟機" msgid "Other removable devices" -msgstr "其他卸除式裝置" +msgstr "其他抽取式裝置" msgid "Other peripherals" msgstr "其他周邊裝置" @@ -790,13 +818,13 @@ msgid "File" msgstr "檔案" msgid "C" -msgstr "C" +msgstr "磁柱" msgid "H" -msgstr "H" +msgstr "磁頭" msgid "S" -msgstr "S" +msgstr "磁區" msgid "KB" msgstr "KB" @@ -811,10 +839,10 @@ msgid "Type" msgstr "類型" msgid "No PCap devices found" -msgstr "未找到 PCap 裝置" +msgstr "未發現 PCap 裝置" msgid "Invalid PCap device" -msgstr "無效 PCap 裝置" +msgstr "無效的 PCap 裝置" msgid "Generic paddle controller(s)" msgstr "通用旋鈕控制器" @@ -856,19 +884,16 @@ msgid "4-axis, 4-button joystick" msgstr "4 軸, 4 鍵搖桿" msgid "2-button gamepad(s)" -msgstr "2 鍵遊戲手柄" +msgstr "2 鍵遊戲手把" msgid "3-button gamepad" -msgstr "3 鍵遊戲手柄" +msgstr "3 鍵遊戲手把" msgid "4-button gamepad" -msgstr "4 鍵遊戲手柄" +msgstr "4 鍵遊戲手把" msgid "6-button gamepad" -msgstr "6 鍵遊戲手柄" - -msgid "Gravis PC GamePad" -msgstr "Gravis PC GamePad" +msgstr "6 鍵遊戲手把" msgid "2-button flight yoke" msgstr "2 按鈕飛行搖桿" @@ -889,64 +914,19 @@ msgid "4-button flight yoke with throttle" msgstr "4 按鈕帶油門飛行搖桿" msgid "Steering wheel (3-axis, 2-button)" -msgstr "方向盤 (3 軸, 2 鍵搖桿)" +msgstr "方向盤 (3 軸, 2 鍵)" msgid "Steering wheel (3-axis, 3-button)" -msgstr "方向盤 (3 軸, 3 鍵搖桿)" +msgstr "方向盤 (3 軸, 3 鍵)" msgid "Steering wheel (3-axis, 4-button)" -msgstr "方向盤 (3 軸, 4 鍵搖桿)" - -msgid "CH Flightstick" -msgstr "CH Flightstick" - -msgid "CH Flightstick + CH Pedals" -msgstr "CH Flightstick + CH Pedals" - -msgid "CH Flightstick + CH Pedals Pro" -msgstr "CH Flightstick + CH Pedals Pro" - -msgid "CH Flightstick Pro" -msgstr "CH Flightstick Pro" - -msgid "CH Flightstick Pro + CH Pedals" -msgstr "CH Flightstick Pro + CH Pedals" - -msgid "CH Flightstick Pro + CH Pedals Pro" -msgstr "CH Flightstick Pro + CH Pedals Pro" - -msgid "CH Virtual Pilot" -msgstr "CH Virtual Pilot" - -msgid "CH Virtual Pilot + CH Pedals" -msgstr "CH Virtual Pilot + CH Pedals" - -msgid "CH Virtual Pilot + CH Pedals Pro" -msgstr "CH Virtual Pilot + CH Pedals Pro" - -msgid "CH Virtual Pilot Pro" -msgstr "CH Virtual Pilot Pro" - -msgid "CH Virtual Pilot Pro + CH Pedals" -msgstr "CH Virtual Pilot Pro + CH Pedals" - -msgid "CH Virtual Pilot Pro + CH Pedals Pro" -msgstr "CH Virtual Pilot Pro + CH Pedals Pro" - -msgid "Microsoft SideWinder Pad" -msgstr "Microsoft SideWinder Pad" - -msgid "Thrustmaster Flight Control System" -msgstr "Thrustmaster Flight Control System" - -msgid "Thrustmaster FCS + Rudder Control System" -msgstr "Thrustmaster FCS + Rudder Control System" +msgstr "方向盤 (3 軸, 4 鍵)" msgid "Thrustmaster Formula T1/T2 with adapter" -msgstr "附轉接器 Thrustmaster Formula T1/T2" +msgstr "Thrustmaster Formula T1/T2 附轉接器" msgid "Thrustmaster Formula T1/T2 without adapter" -msgstr "不附轉接器 Thrustmaster Formula T1/T2" +msgstr "Thrustmaster Formula T1/T2 不附轉接器" msgid "None" msgstr "無" @@ -996,11 +976,17 @@ msgstr "內部裝置" msgid "&File" msgstr "檔案(&F)" -msgid "&New machine..." -msgstr "新機器(&N)..." +msgid "&New machine…" +msgstr "新機器(&N)…" -msgid "&Check for updates..." -msgstr "檢查更新(&C)..." +msgid "New machine…" +msgstr "新機器…" + +msgid "New machine" +msgstr "新機器" + +msgid "&Check for updates…" +msgstr "檢查更新(&C)…" msgid "Exit" msgstr "退出" @@ -1021,7 +1007,7 @@ msgid "About %1" msgstr "關於 %1" msgid "An emulator of old computers\n\nAuthors: Miran Grča (OBattler), RichardG867, Jasmine Iwanek, TC1995, coldbrewed, Teemu Korhonen (Manaatti), Joakim L. Gilje, Adrien Moulin (elyosh), Daniel Balsom (gloriouscow), Cacodemon345, Fred N. van Kempen (waltje), Tiseno100, reenigne, and others.\n\nWith previous core contributions from Sarah Walker, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2 or later. See LICENSE for more information." -msgstr "一個舊式電腦模擬器\n\n作者: Miran Grča (OBattler)、RichardG867、Jasmine Iwanek、TC1995、coldbrewed、Teemu Korhonen (Manaatti)、Joakim L. Gilje、Adrien Moulin (elyosh)、Daniel Balsom (gloriouscow)、Cacodemon345、Fred N. van Kempen (waltje)、Tiseno100、reenigne 等人。\n\n之前的核心貢獻來自 Sarah Walker、leilei、JohnElliott、greatpsycho 等人。\n\n本軟體依據 GNU 通用公共授權第二版或更新版本發佈。詳情見 LICENSE 檔案。" +msgstr "一個舊式電腦模擬器\n\n作者: Miran Grča (OBattler)、RichardG867、Jasmine Iwanek、TC1995、coldbrewed、Teemu Korhonen (Manaatti)、Joakim L. Gilje、Adrien Moulin (elyosh)、Daniel Balsom (gloriouscow)、Cacodemon345、Fred N. van Kempen (waltje)、Tiseno100、reenigne 等人。\n\n之前的核心貢獻來自 Sarah Walker、leilei、JohnElliott、greatpsycho 等人。\n\n本軟體依據 GNU 通用公眾授權條款第二版或更新版本發佈。詳情見 LICENSE 檔案。" msgid "Hardware not available" msgstr "硬體不可用" @@ -1030,7 +1016,7 @@ msgid "Make sure %1 is installed and that you are on a %1-compatible network con msgstr "請確認 %1 已安裝且使用相容 %1 的網路連線。" msgid "Invalid configuration" -msgstr "無效設定" +msgstr "無效組態" msgid "%1 is required for automatic conversion of PostScript files to PDF.\n\nAny documents sent to the generic PostScript printer will be saved as PostScript (.ps) files." msgstr "自動將 PostScript 檔案轉換為 PDF 需要 %1。\n\n使用通用 PostScript 印表機列印的文件將被儲存為 PostScript (.ps) 檔案。" @@ -1039,7 +1025,7 @@ msgid "%1 is required for automatic conversion of PCL files to PDF.\n\nAny docum msgstr "自動將 PCL 檔案轉換為 PDF 需要 %1。\n\n使用通用 PCL 印表機列印的文件將被儲存為 Printer Command Language (.pcl) 檔案。" msgid "Don't show this message again" -msgstr "不要再顯示此消息" +msgstr "不要再顯示此訊息" msgid "Don't exit" msgstr "不退出" @@ -1054,7 +1040,7 @@ msgid "CD-ROM images" msgstr "光碟影像" msgid "%1 Device Configuration" -msgstr "%1 裝置設定" +msgstr "%1 裝置組態" msgid "Monitor in sleep mode" msgstr "監視器處在睡眠狀態" @@ -1063,7 +1049,7 @@ msgid "GLSL shaders" msgstr "GLSL 著色器" msgid "You are loading an unsupported configuration" -msgstr "正在載入一個不受支援的設定" +msgstr "正在載入一個不受支援的組態" msgid "CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid." msgstr "此模擬電腦停用了基於選定電腦的 CPU 類型過濾。\n\n能夠選中與所選機器本不相容的 CPU,但是可能會遇到與機器 BIOS 或其他軟體不相容的問題。\n\n啟用此設定不受官方支援,並且提交的任何錯誤報告可能會視為無效而結案。" @@ -1156,22 +1142,22 @@ msgid "Choose directory" msgstr "選擇目錄" msgid "Choose configuration file" -msgstr "選擇設定檔" +msgstr "選擇組態檔" msgid "86Box configuration files (86box.cfg)" -msgstr "86Box 設定檔 (86box.cfg)" +msgstr "86Box 組態檔 (86box.cfg)" msgid "Configuration read failed" -msgstr "設定讀取失敗" +msgstr "組態讀取失敗" msgid "Unable to open the selected configuration file for reading: %1" -msgstr "無法開啟選取的設定檔進行讀取: %1" +msgstr "無法開啟選取的組態檔進行讀取: %1" msgid "Use regular expressions in search box" -msgstr "在搜尋方塊中使用正規表示式" +msgstr "在搜尋欄中使用正規表示式" -msgid "%1 machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" -msgstr "%1 台機器目前處於活動狀態。您確定要退出虛擬機器管理員嗎?" +msgid "%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?" +msgstr "%n 台機器目前處於活動狀態。您確定要退出虛擬機器管理員嗎?" msgid "Add new system wizard" msgstr "新增系統精靈" @@ -1180,28 +1166,28 @@ msgid "Introduction" msgstr "簡介" msgid "This will help you add a new system to 86Box." -msgstr "這將有助於您在 86Box 中加入新系統。" +msgstr "這將協助您在 86Box 中加入新系統。" msgid "New configuration" -msgstr "新增設定" +msgstr "新增組態" msgid "Complete" msgstr "完成" msgid "The wizard will now launch the configuration for the new system." -msgstr "精靈現在會啟動新系統的設定。" +msgstr "精靈現在會啟動新系統的組態。" msgid "Use existing configuration" -msgstr "使用現有設定" +msgstr "使用現有組態" msgid "Type some notes here" msgstr "在此輸入備註" msgid "Paste the contents of the existing configuration file into the box below." -msgstr "將現有設定檔的內容貼到下面的方塊中。" +msgstr "將現有組態檔的內容貼到下面的輸入欄中。" msgid "Load configuration from file" -msgstr "從檔案載入設定" +msgstr "從檔案載入組態" msgid "System name" msgstr "系統名稱" @@ -1251,26 +1237,23 @@ msgstr "設定顯示名稱" msgid "Enter the new display name (blank to reset)" msgstr "輸入新的顯示名稱 (留空以重設)" -msgid "Change &display name..." -msgstr "變更顯示名稱(&D)..." - -msgid "Context Menu" -msgstr "內容選單" +msgid "Change &display name…" +msgstr "變更顯示名稱(&D)…" -msgid "&Open folder..." -msgstr "開啟資料夾(&O)..." +msgid "&Open folder…" +msgstr "開啟資料夾(&O)…" -msgid "Open p&rinter tray..." -msgstr "開啟印表機托盤(&R)..." +msgid "Open p&rinter tray…" +msgstr "開啟印表機托盤(&R)…" -msgid "Set &icon..." -msgstr "設定圖示(&I)..." +msgid "Set &icon…" +msgstr "設定圖示(&I)…" msgid "Select an icon" msgstr "選擇圖示" -msgid "C&lone..." -msgstr "複製(&L)..." +msgid "C&lone…" +msgstr "複製(&L)…" msgid "Virtual machine \"%1\" (%2) will be cloned into:" msgstr "虛擬機器 \"%1\" (%2) 將被複製到:" @@ -1303,10 +1286,10 @@ msgid "Unable to create the directory for the new system" msgstr "無法為新系統建立目錄" msgid "Configuration write failed" -msgstr "設定寫入失敗" +msgstr "組態寫入失敗" msgid "Unable to open the configuration file at %1 for writing" -msgstr "無法開啟 %1 的設定檔進行寫入" +msgstr "無法開啟 %1 的組態檔進行寫入" msgid "Error adding system" msgstr "新增系統錯誤" @@ -1330,7 +1313,7 @@ msgid "An error has occurred while checking for updates: %1" msgstr "檢查更新時發生錯誤: %1" msgid "An update to 86Box is available!" -msgstr "86Box 的更新可用!" +msgstr "有 86Box 的更新可用!" msgid "Warning" msgstr "警告" @@ -1339,25 +1322,25 @@ msgid "&Kill" msgstr "強制終止(&K)" msgid "Killing a virtual machine can cause data loss. Only do this if the 86Box process gets stuck.\n\nDo you really wish to kill the virtual machine \"%1\"?" -msgstr "強行終止虛擬機器可能會導致資料遺失。只有在 86Box 過程卡住時才執行此操作。\n\n您真的希望強制終止虛擬機器 \"%1\"?" +msgstr "強制終止虛擬機器可能會導致資料遺失。只有在 86Box 過程卡住時才執行此操作。\n\n您真的希望強制終止虛擬機器 \"%1\"?" msgid "&Delete" msgstr "刪除(&D)" msgid "Do you really want to delete the virtual machine \"%1\" and all its files? This action cannot be undone!" -msgstr "您真的想要刪除虛擬機器 \"%1\" 及其所有檔案嗎?此操作無法撤銷!" +msgstr "您真的想要刪除虛擬機器 \"%1\" 及其所有檔案嗎?此操作無法回復!" msgid "Show &config file" -msgstr "顯示設定檔(&C)" +msgstr "顯示組態檔(&C)" msgid "No screenshot" -msgstr "沒有擷圖" +msgstr "沒有螢幕畫面擷取" msgid "Search" msgstr "搜尋" -msgid "Searching for VMs..." -msgstr "搜尋虛擬機器..." +msgid "Searching for VMs…" +msgstr "搜尋虛擬機器…" msgid "Found %1" msgstr "找到 %1" @@ -1384,7 +1367,7 @@ msgid "ACPI shutdown" msgstr "ACPI 關機" msgid "ACP&I shutdown" -msgstr "ACP&I 關機" +msgstr "ACPI 關機(&I)" msgid "Hard disk (%1)" msgstr "硬碟 (%1)" @@ -1392,11 +1375,11 @@ msgstr "硬碟 (%1)" msgid "MFM/RLL or ESDI CD-ROM drives never existed" msgstr "MFM/RLL 或 ESDI CD-ROM 光碟機從未存在" -msgid "Custom..." -msgstr "自訂..." +msgid "Custom…" +msgstr "自訂…" -msgid "Custom (large)..." -msgstr "自訂 (大容量)..." +msgid "Custom (large)…" +msgstr "自訂 (大容量)…" msgid "Add New Hard Disk" msgstr "增加新硬碟" @@ -1441,7 +1424,7 @@ msgid "Disk image too large" msgstr "磁碟影像太大" msgid "Remember to partition and format the newly-created drive." -msgstr "請記得為新創建的影像分區並格式化。" +msgstr "請記得為新創建的影像建立分割區並格式化。" msgid "The selected file will be overwritten. Are you sure you want to use it?" msgstr "選定的檔案將被覆蓋。確定繼續使用此檔案嗎?" @@ -1450,10 +1433,10 @@ msgid "Unsupported disk image" msgstr "不支援的磁碟影像" msgid "Overwrite" -msgstr "覆蓋" +msgstr "覆寫" msgid "Don't overwrite" -msgstr "不覆蓋" +msgstr "不覆寫" msgid "Raw image" msgstr "原始影像" @@ -1471,7 +1454,7 @@ msgid "Dynamic-size VHD" msgstr "動態大小 VHD" msgid "Differencing VHD" -msgstr "差分 VHD" +msgstr "差異影像 VHD" msgid "(N/A)" msgstr "(不適用)" @@ -1492,7 +1475,7 @@ msgid "Dynamic-size VHD (.vhd)" msgstr "動態大小 VHD (.vhd)" msgid "Differencing VHD (.vhd)" -msgstr "差分 VHD (.vhd)" +msgstr "差異影像 VHD (.vhd)" msgid "Large blocks (2 MB)" msgstr "大區塊 (2 MB)" @@ -1515,21 +1498,6 @@ msgstr "父碟與子碟的時間戳不匹配" msgid "Could not fix VHD timestamp." msgstr "無法修復 VHD 時間戳。" -msgid "MFM/RLL" -msgstr "MFM/RLL" - -msgid "XTA" -msgstr "XTA" - -msgid "ESDI" -msgstr "ESDI" - -msgid "IDE" -msgstr "IDE" - -msgid "ATAPI" -msgstr "ATAPI" - msgid "CD-ROM %1 (%2): %3" msgstr "光碟 %1 (%2): %3" @@ -1624,7 +1592,7 @@ msgid "Failed to initialize network driver" msgstr "初始化網路驅動程式失敗" msgid "The network configuration will be switched to the null driver" -msgstr "網路設定將切換為空驅動程式" +msgstr "網路組態將切換為空驅動程式" msgid "Mouse sensitivity:" msgstr "滑鼠靈敏度:" @@ -1651,13 +1619,13 @@ msgid "WinBox is no longer supported" msgstr "不再支援 WinBox" msgid "Development of the WinBox manager stopped in 2022 due to a lack of maintainers. As we direct our efforts towards making 86Box even better, we have made the decision to no longer support WinBox as a manager.\n\nNo further updates will be provided through WinBox, and you may encounter incorrect behavior should you continue using it with newer versions of 86Box. Any bug reports related to WinBox behavior will be closed as invalid.\n\nGo to 86box.net for a list of other managers you can use." -msgstr "WinBox 於 2022 年因缺乏維護者而停止發展。由於我們傾注全力於將 86Box 做的更好,我們決定不再支援將 WinBox 做為管理員。\n\n在 WinBox 未提供更新前,搭配新版本的 86Box 使用將導致不正確的行為。任何由 WinBox 引起的錯誤回報將以無效結案。\n\n請造訪 86box.net 網站以取得其他可用的管理員列表。" +msgstr "WinBox 於 2022 年因缺乏維護者而停止發展。由於我們傾注全力於將 86Box 做的更好,我們決定不再支援將 WinBox 做為前端管理程式。\n\n在 WinBox 未提供更新前,搭配新版本的 86Box 使用將導致不正確的行為。任何由 WinBox 引起的錯誤回報將以無效結案。\n\n請造訪 86box.net 網站以取得其他可用的前端管理程式列表。" msgid "Generate" msgstr "產生" msgid "Joystick configuration" -msgstr "搖桿設定" +msgstr "搖桿組態" msgid "Device" msgstr "裝置" @@ -1680,14 +1648,14 @@ msgstr "平板工具(&T)" msgid "About &Qt" msgstr "關於 &Qt" -msgid "&MCA devices..." -msgstr "&MCA 裝置..." +msgid "&MCA devices…" +msgstr "&MCA 裝置…" msgid "Show non-&primary monitors" msgstr "顯示非主要監視器(&P)" -msgid "Open screenshots &folder..." -msgstr "開啟螢幕擷圖資料夾(&F)..." +msgid "Open screenshots &folder…" +msgstr "開啟螢幕畫面擷取資料夾(&F)…" msgid "Appl&y fullscreen stretch mode when maximized" msgstr "最大化時套用全螢幕延展模式(&Y)" @@ -1707,8 +1675,8 @@ msgstr "已連線(&C)" msgid "Clear image &history" msgstr "清除影像歷史記錄(&H)" -msgid "Create..." -msgstr "建立..." +msgid "Create…" +msgstr "建立…" msgid "Host CD/DVD Drive (%1)" msgstr "主機 CD/DVD 光碟機 (%1)" @@ -1720,13 +1688,13 @@ msgid "Null Driver" msgstr "空驅動程式" msgid "NIC:" -msgstr "網路卡:" +msgstr "網路介面控制器:" msgid "NIC %1 (%2) %3" -msgstr "網路卡 %1 (%2) %3" +msgstr "網路介面控制器 %1 (%2) %3" msgid "&NIC %1 (%2) %3" -msgstr "網路卡 %1 (%2) %3(&N)" +msgstr "網路介面控制器 %1 (%2) %3(&N)" msgid "Render behavior" msgstr "渲染行為" @@ -1749,8 +1717,8 @@ msgstr "著色器" msgid "Remove" msgstr "移除" -msgid "Browse..." -msgstr "瀏覽..." +msgid "Browse…" +msgstr "瀏覽…" msgid "Couldn't create OpenGL context." msgstr "無法建立 OpenGL 內容。" @@ -1759,16 +1727,16 @@ msgid "Couldn't switch to OpenGL context." msgstr "無法切換至 OpenGL 內容。" msgid "OpenGL version 3.0 or greater is required. Current version is %1.%2" -msgstr "需要 OpenGL 版本 3.0 或更高。目前版本為 %1.%2" +msgstr "需要 OpenGL 版本 3.0 或更高版本。目前版本為 %1.%2" msgid "Error initializing OpenGL" -msgstr "初始化 OpenGL 出錯" +msgstr "初始化 OpenGL 錯誤" msgid "\nFalling back to software rendering." -msgstr "\n回退到軟體渲染。" +msgstr "\n退回到軟體渲染。" msgid "

When selecting media images (CD-ROM, floppy, etc.) the open dialog will start in the same directory as the 86Box configuration file. This setting will likely only make a difference on macOS.

" -msgstr "

當選擇媒體影像 (CD-ROM、軟碟等) 時,開啟對話方塊會在與 86Box 設定檔相同的目錄中開始。此設定可能只會在 macOS 上有所影響。

" +msgstr "

當選擇媒體影像 (CD-ROM、軟碟等) 時,開啟對話框會在與 86Box 組態檔相同的目錄中開始。此設定可能只會在 macOS 上有所影響。

" msgid "This machine might have been moved or copied." msgstr "這台機器可能已被移動或複製。" @@ -1839,8 +1807,8 @@ msgstr "序列埠的直通 3" msgid "Serial port passthrough 4" msgstr "序列埠的直通 4" -msgid "Renderer &options..." -msgstr "渲染器選項(&O)..." +msgid "Renderer &options…" +msgstr "渲染器選項(&O)…" msgid "PC/XT Keyboard" msgstr "PC/XT 鍵盤" @@ -1893,8 +1861,8 @@ msgstr "3M MicroTouch (序列埠)" msgid "Default Baud rate" msgstr "預設鮑率" -msgid "[COM] Standard Hayes-compliant Modem" -msgstr "[COM] 標準 Hayes 相容的數據機" +msgid "Standard Hayes-compliant Modem" +msgstr "標準 Hayes 相容的數據機" msgid "Roland MT-32 Emulation" msgstr "Roland MT-32 模擬" @@ -1963,7 +1931,7 @@ msgid "Enable BIOS extension ROM Writes (ROM #4)" msgstr "啟用 BIOS 擴充 ROM 寫入 (ROM 4)" msgid "Linear framebuffer base" -msgstr "線性圖框緩衝記憶體的起始位址" +msgstr "線性影格緩衝記憶體的起始位址" msgid "Address" msgstr "位址" @@ -1977,6 +1945,9 @@ msgstr "序列埠的 IRQ" msgid "Parallel port IRQ" msgstr "並列埠的 IRQ" +msgid "Hard disk" +msgstr "硬碟" + msgid "BIOS Revision" msgstr "BIOS 修訂版號" @@ -2008,7 +1979,7 @@ msgid "BIOS size" msgstr "BIOS 大小" msgid "BIOS size (ROM #1)" -msgstr "BIOS 大小 (ROM )" +msgstr "BIOS 大小 (ROM 1)" msgid "BIOS size (ROM #2)" msgstr "BIOS 大小 (ROM 2)" @@ -2050,10 +2021,7 @@ msgid "MIDI Thru" msgstr "MIDI 輸入直通" msgid "MIDI Clockout" -msgstr "MIDI 時鐘輸出" - -msgid "SoundFont" -msgstr "SoundFont" +msgstr "MIDI 時脈輸出" msgid "Output Gain" msgstr "輸出增益" @@ -2077,19 +2045,19 @@ msgid "Chorus Waveform" msgstr "合唱波形" msgid "Reverb" -msgstr "混響" +msgstr "殘響" msgid "Reverb Room Size" -msgstr "混響室的大小" +msgstr "殘響室的大小" msgid "Reverb Damping" -msgstr "混響阻尼" +msgstr "殘響阻尼" msgid "Reverb Width" -msgstr "混響寬度" +msgstr "殘響寬度" msgid "Reverb Level" -msgstr "混響位準" +msgstr "殘響位準" msgid "Interpolation Method" msgstr "插值方法" @@ -2098,10 +2066,10 @@ msgid "Dynamic Sample Loading" msgstr "動態取樣載入" msgid "Reverb Output Gain" -msgstr "迴響輸出增益" +msgstr "殘響輸出增益" msgid "Reversed stereo" -msgstr "反向立體聲" +msgstr "左右互換立體聲" msgid "Nice ramp" msgstr "平滑漸變曲線" @@ -2161,7 +2129,7 @@ msgid "Initial RAM size" msgstr "初始 RAM 大小" msgid "Serial Number" -msgstr "序列號" +msgstr "序號" msgid "Host ID" msgstr "主機 ID" @@ -2233,7 +2201,7 @@ msgid "SB low DMA" msgstr "SB 低 DMA" msgid "6CH variant (6-channel)" -msgstr "6CH 變數 (6 通道)" +msgstr "6CH 變體 (6 通道)" msgid "Enable CMS" msgstr "啟用 CMS" @@ -2383,7 +2351,7 @@ msgid "Address for > 2 MB" msgstr "> 2 MB 的位址" msgid "Frame Address" -msgstr "影格位址" +msgstr "頁框位址" msgid "USA" msgstr "美國" @@ -2419,7 +2387,7 @@ msgid "7th Order" msgstr "七階" msgid "Non-timed (original)" -msgstr "非定時 (原始)" +msgstr "無計時 (原始)" msgid "45 Hz (JMP2 not populated)" msgstr "45 Hz (JMP2 未安插)" @@ -2542,7 +2510,7 @@ msgid "Has Quadcolor II daughter board" msgstr "具有 Quadcolor II 子板" msgid "Alternate monochrome contrast" -msgstr "交替單色對比" +msgstr "反轉單色對比" msgid "128 KB" msgstr "128 KB" @@ -2563,10 +2531,10 @@ msgid "Color 80x25 (5153/CGA)" msgstr "彩色 80x25 (5153/CGA)" msgid "Enhanced Color - Normal Mode (5154/ECD)" -msgstr "增強彩色 - 一般模式 (5154/ECD)" +msgstr "增強色彩 - 一般模式 (5154/ECD)" msgid "Enhanced Color - Enhanced Mode (5154/ECD)" -msgstr "增強彩色 - 增強模式 (5154/ECD)" +msgstr "增強色彩 - 增強模式 (5154/ECD)" msgid "Green" msgstr "綠色" @@ -2602,13 +2570,13 @@ msgid "Mono Interlaced" msgstr "單色隔行掃描" msgid "Mono Non-Interlaced" -msgstr "單色非隔行掃描" +msgstr "單色逐行掃描" msgid "Color Interlaced" msgstr "彩色隔行掃描" msgid "Color Non-Interlaced" -msgstr "彩色非隔行掃描" +msgstr "彩色逐行掃描" msgid "3Dfx Voodoo Graphics" msgstr "3Dfx Voodoo 圖形" @@ -2701,7 +2669,7 @@ msgid "Softfloat FPU" msgstr "Softfloat 浮點運算器模擬" msgid "High performance impact" -msgstr "對效能影響大" +msgstr "對效能影響高" msgid "[Generic] RAM Disk (max. speed)" msgstr "[通用] RAM 磁碟 (最大速度)" @@ -2794,7 +2762,7 @@ msgid "Shader Manager" msgstr "著色器管理員" msgid "Shader Configuration" -msgstr "著色器設定" +msgstr "著色器組態" msgid "Add" msgstr "新增" @@ -2809,28 +2777,28 @@ msgid "Could not load file %1" msgstr "無法載入檔案 %1" msgid "Key Bindings:" -msgstr "按鍵綁定:" +msgstr "按鍵組合:" msgid "Action" -msgstr "行動" +msgstr "動作" msgid "Keybind" -msgstr "鍵盤綁定" +msgstr "按鍵組合" msgid "Clear binding" -msgstr "解除綁定" +msgstr "解除組合" msgid "Bind" -msgstr "綁定" +msgstr "組合" msgid "Bind Key" -msgstr "綁定按鍵" +msgstr "組合按鍵" msgid "Enter key combo:" msgstr "輸入組合鍵:" msgid "Bind conflict" -msgstr "綁定衝突" +msgstr "組合衝突" msgid "This key combo is already in use." msgstr "此組合鍵已在使用中。" @@ -2845,10 +2813,7 @@ msgid "Toggle fullscreen" msgstr "切換全螢幕" msgid "Toggle UI in fullscreen" -msgstr "切換使用者介面至全螢幕" - -msgid "Screenshot" -msgstr "螢幕擷圖" +msgstr "全螢幕模式下切換使用者介面顯示" msgid "Release mouse pointer" msgstr "放開滑鼠游標" @@ -2923,7 +2888,7 @@ msgid "Unable to determine release information" msgstr "無法確定版本發佈資訊" msgid "There was an error checking for updates:\n\n%1\n\nPlease try again later." -msgstr "檢查更新時出錯:\n\n%1\n\n請稍後再試。" +msgstr "檢查更新時錯誤:\n\n%1\n\n請稍後再試。" msgid "Update check complete" msgstr "更新檢查完成" @@ -2964,14 +2929,14 @@ msgstr "造訪下載頁面" msgid "Update check" msgstr "更新檢查" -msgid "Checking for updates..." -msgstr "正在檢查更新..." +msgid "Checking for updates…" +msgstr "正在檢查更新…" msgid "86Box Update" msgstr "86Box 更新" msgid "Release notes:" -msgstr "版本發佈說明:" +msgstr "版本發佈備註:" msgid "%1 Hz" msgstr "%1 Hz" @@ -2980,13 +2945,13 @@ msgid "Virtual machine crash" msgstr "虛擬機當機" msgid "The virtual machine \"%1\"'s process has unexpectedly terminated with exit code %2." -msgstr "虛擬機 \"%1\" 的進程以退出代碼 %2 意外終止。" +msgstr "虛擬機 \"%1\" 的行程以結束碼 %2 意外終止。" msgid "The system will not be added." msgstr "系統將不會被新增。" msgid "&Update mouse every CPU frame" -msgstr "每 CPU 幀更新滑鼠(&U)" +msgstr "每 CPU 執行期框架更新滑鼠(&U)" msgid "Hue" msgstr "色調" @@ -3003,8 +2968,8 @@ msgstr "亮度" msgid "Sharpness" msgstr "銳利度" -msgid "&CGA composite settings..." -msgstr "CGA 複合視訊的設定(&C)..." +msgid "&CGA composite settings…" +msgstr "CGA 複合視訊的設定(&C)…" msgid "CGA composite settings" msgstr "CGA 複合視訊的設定" @@ -3012,8 +2977,8 @@ msgstr "CGA 複合視訊的設定" msgid "Monitor EDID" msgstr "監視器的 EDID" -msgid "Export..." -msgstr "匯出..." +msgid "Export…" +msgstr "匯出…" msgid "Export EDID" msgstr "匯出 EDID" @@ -3028,7 +2993,7 @@ msgid "OpenGL input stretch mode" msgstr "OpenGL 的輸入延展模式" msgid "Color scheme" -msgstr "配色方案" +msgstr "色彩配置" msgid "Light" msgstr "亮色" @@ -3038,3 +3003,24 @@ msgstr "暗色" msgid "Search:" msgstr "搜尋:" + +msgid "Force interpretation" +msgstr "強制解譯執行" + +msgid "Allow recompilation" +msgstr "允許重編譯" + +msgid "&Force interpretation" +msgstr "強制解譯執行(&F)" + +msgid "&Allow recompilation" +msgstr "允許重編譯(&A)" + +msgid "&Fast forward" +msgstr "快轉(&F)" + +msgid "Fast forward" +msgstr "快轉" + +msgid "To change the system directory, stop all running machines." +msgstr "欲變更系統目錄,請先停止全部運行中的機器。" diff --git a/src/qt/qt_deviceconfig.cpp b/src/qt/qt_deviceconfig.cpp index 7cc39898873..42d63243d82 100644 --- a/src/qt/qt_deviceconfig.cpp +++ b/src/qt/qt_deviceconfig.cpp @@ -492,8 +492,18 @@ DeviceConfig::DeviceName(const _device_ *device, const char *internalName, const else if (device == nullptr) return ""; else { - char temp[512]; - device_get_name(device, bus, temp); - return tr((const char *) temp); + char temp[512]; + const char *tempbus; + if (bus == 1) { + device_get_name(device, -1, temp); + tempbus = device_get_bus_name(device); + if (tempbus != nullptr) + return QString("[%1] %2").arg(tr(tempbus), tr((const char *) temp)); + else + return tr((const char *) temp); + } else { + device_get_name(device, bus, temp); + return tr((const char *) temp); + } } } diff --git a/src/qt/qt_filefield.ui b/src/qt/qt_filefield.ui index 91000af50d1..33e8a7b21be 100644 --- a/src/qt/qt_filefield.ui +++ b/src/qt/qt_filefield.ui @@ -51,7 +51,7 @@ - Browse... + Browse… diff --git a/src/qt/qt_harddiskdialog.cpp b/src/qt/qt_harddiskdialog.cpp index fbb6a476897..1c6345f26c9 100644 --- a/src/qt/qt_harddiskdialog.cpp +++ b/src/qt/qt_harddiskdialog.cpp @@ -78,8 +78,8 @@ HarddiskDialog::HarddiskDialog(bool existing, QWidget *parent) QString text = tr("%1 MB (CHS: %2, %3, %4)").arg(size_mb).arg(hdd_table[i][0]).arg(hdd_table[i][1]).arg(hdd_table[i][2]); Models::AddEntry(model, text, i); } - Models::AddEntry(model, tr("Custom..."), 127); - Models::AddEntry(model, tr("Custom (large)..."), 128); + Models::AddEntry(model, tr("Custom…"), 127); + Models::AddEntry(model, tr("Custom (large)…"), 128); ui->lineEditSize->setValidator(new QIntValidator()); ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); diff --git a/src/qt/qt_harddrive_common.cpp b/src/qt/qt_harddrive_common.cpp index 1c07e5f3ff5..7ec75d47d9c 100644 --- a/src/qt/qt_harddrive_common.cpp +++ b/src/qt/qt_harddrive_common.cpp @@ -17,6 +17,7 @@ #include extern "C" { +#include <86box/86box.h> #include <86box/hdd.h> #include <86box/scsi.h> #include <86box/cdrom.h> @@ -57,13 +58,13 @@ Harddrives::populateCDROMBuses(QAbstractItemModel *model) #endif model->setData(model->index(0, 0), QObject::tr("Disabled")); - model->setData(model->index(1, 0), QObject::tr("ATAPI")); - model->setData(model->index(2, 0), QObject::tr("SCSI")); + model->setData(model->index(1, 0), "ATAPI"); + model->setData(model->index(2, 0), "SCSI"); #ifdef USE_CDROM_MITSUMI - model->setData(model->index(3, 0), QObject::tr("Mitsumi")); - model->setData(model->index(4, 0), QObject::tr("Panasonic/MKE")); + model->setData(model->index(3, 0), "Mitsumi"); + model->setData(model->index(4, 0), "Panasonic/MKE"); #else - model->setData(model->index(3, 0), QObject::tr("Panasonic/MKE")); + model->setData(model->index(3, 0), "Panasonic/MKE"); #endif model->setData(model->index(0, 0), HDD_BUS_DISABLED, Qt::UserRole); @@ -84,8 +85,8 @@ Harddrives::populateRemovableBuses(QAbstractItemModel *model) model->insertRows(0, 3); model->setData(model->index(0, 0), QObject::tr("Disabled")); - model->setData(model->index(1, 0), QObject::tr("ATAPI")); - model->setData(model->index(2, 0), QObject::tr("SCSI")); + model->setData(model->index(1, 0), "ATAPI"); + model->setData(model->index(2, 0), "SCSI"); model->setData(model->index(0, 0), HDD_BUS_DISABLED, Qt::UserRole); model->setData(model->index(1, 0), HDD_BUS_ATAPI, Qt::UserRole); diff --git a/src/qt/qt_iconindicators.cpp b/src/qt/qt_iconindicators.cpp index b93c375b741..771a9ac59a2 100644 --- a/src/qt/qt_iconindicators.cpp +++ b/src/qt/qt_iconindicators.cpp @@ -6,10 +6,16 @@ QIcon getIndicatorIcon(IconIndicator indicator) { switch (indicator) { + case Play: + return QIcon(":/menuicons/qt/icons/run.ico"); + case Pause: + return QIcon(":/menuicons/qt/icons/pause.ico"); case Active: return QIcon(":/settings/qt/icons/active.ico"); case WriteActive: return QIcon(":/settings/qt/icons/write_active.ico"); + case Record: + return QIcon(":/settings/qt/icons/record.ico"); case Disabled: return QIcon(":/settings/qt/icons/disabled.ico"); case WriteProtected: @@ -36,13 +42,22 @@ getIconWithIndicator(const QIcon &icon, const QSize &size, QIcon::Mode iconMode, return iconPixmap; auto painter = QPainter(&iconPixmap); - auto indicatorPixmap = getIndicatorIcon((indicator == ReadWriteActive || indicator == WriteProtectedActive) ? Active : indicator).pixmap(size); + auto indicatorPixmap = getIndicatorIcon((indicator == ReadWriteActive || indicator == WriteProtectedActive + || indicator == PlayActive || indicator == PauseActive) ? Active : + (indicator == RecordWriteActive) ? Record : indicator) + .pixmap((indicator == Play || indicator == Pause || indicator == Record || indicator == RecordWriteActive) ? size / 2. : size); if (indicator == WriteProtectedBrowse) indicatorPixmap = getIndicatorIcon(WriteProtected).pixmap(size); - painter.drawPixmap(0, 0, indicatorPixmap); - if ((indicator == ReadWriteActive) || (indicator == WriteProtectedActive)) { + if (indicator == Record || indicator == RecordWriteActive) + painter.drawPixmap(size.width() / 2, size.height() / 2, indicatorPixmap); + else + painter.drawPixmap(0, (indicator == Play || indicator == Pause) ? (size.height() / 2) : 0, indicatorPixmap); + if (indicator == PlayActive || indicator == PauseActive) { + auto playPauseIndicatorPixmap = getIndicatorIcon(indicator == PlayActive ? Play : Pause).pixmap(size / 2.); + painter.drawPixmap(0, size.height() / 2, playPauseIndicatorPixmap); + } else if ((indicator == ReadWriteActive) || (indicator == WriteProtectedActive) || (indicator == RecordWriteActive)) { auto writeIndicatorPixmap = getIndicatorIcon(indicator == WriteProtectedActive ? WriteProtected : WriteActive).pixmap(size); painter.drawPixmap(0, 0, writeIndicatorPixmap); } else if (indicator == WriteProtectedBrowse) { diff --git a/src/qt/qt_iconindicators.hpp b/src/qt/qt_iconindicators.hpp index 24ce80ad370..971ab6ead0e 100644 --- a/src/qt/qt_iconindicators.hpp +++ b/src/qt/qt_iconindicators.hpp @@ -16,7 +16,13 @@ enum IconIndicator { Browse, WriteProtectedBrowse, Export, - Eject + Eject, + Play, + Pause, + PlayActive, + PauseActive, + Record, + RecordWriteActive }; QPixmap getIconWithIndicator(const QIcon &icon, const QSize &size, QIcon::Mode iconMode, IconIndicator indicator); diff --git a/src/qt/qt_machinestatus.cpp b/src/qt/qt_machinestatus.cpp index 2e6203f24d8..e6f6c824e81 100644 --- a/src/qt/qt_machinestatus.cpp +++ b/src/qt/qt_machinestatus.cpp @@ -17,9 +17,9 @@ #include "qt_machinestatus.hpp" extern "C" { +#include <86box/86box.h> #include <86box/hdd.h> #include <86box/timer.h> -#include <86box/86box.h> #include <86box/device.h> #include <86box/cartridge.h> #include <86box/cassette.h> @@ -83,9 +83,15 @@ struct PixmapSetEmpty { struct PixmapSetEmptyActive { QPixmap normal; QPixmap active; + QPixmap record; + QPixmap play; + QPixmap pause; + QPixmap play_active; + QPixmap pause_active; QPixmap empty; QPixmap empty_active; QPixmap write_active; + QPixmap record_write_active; QPixmap read_write_active; QPixmap empty_write_active; QPixmap empty_read_write_active; @@ -169,6 +175,36 @@ struct StateEmptyActive { bool active = false; bool write_active = false; bool wp = false; + bool play = false; + bool pause = false; + bool record = false; + + void setRecord(bool b) + { + if (!label || b == record) + return; + + record = b; + refresh(); + } + + void setPlay(bool b) + { + if (!label || b == play) + return; + + play = b; + refresh(); + } + + void setPause(bool b) + { + if (!label || b == pause) + return; + + pause = b; + refresh(); + } void setActive(bool b) { @@ -212,10 +248,14 @@ struct StateEmptyActive { else label->setPixmap(write_active ? pixmaps->empty_write_active : (active ? pixmaps->empty_active : pixmaps->empty)); } else { - if (wp) + if (wp && !(play || pause)) label->setPixmap(active ? pixmaps->wp_active : pixmaps->wp); - else if (active && write_active) + else if (active && write_active && !wp) label->setPixmap(pixmaps->read_write_active); + else if (record && !active && !wp) + label->setPixmap(write_active ? pixmaps->record_write_active : pixmaps->record); + else if ((play || pause) && !write_active) + label->setPixmap(play ? (active ? pixmaps->play_active : pixmaps->play) : (active ? pixmaps->pause_active : pixmaps->pause)); else label->setPixmap(write_active ? pixmaps->write_active : (active ? pixmaps->active : pixmaps->normal)); } @@ -252,10 +292,16 @@ void PixmapSetEmptyActive::load(const QIcon &icon) { normal = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, None); + play = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, Play); + pause = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, Pause); + record = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, Record); + play_active = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, PlayActive); + pause_active = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, PauseActive); wp = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, WriteProtected); wp_active = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, WriteProtectedActive); active = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, Active); write_active = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, WriteActive); + record_write_active = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, RecordWriteActive); read_write_active = getIconWithIndicator(icon, pixmap_size, QIcon::Normal, ReadWriteActive); empty = getIconWithIndicator(icon, pixmap_size, QIcon::Disabled, None); empty_active = getIconWithIndicator(icon, pixmap_size, QIcon::Disabled, Active); @@ -495,10 +541,21 @@ MachineStatus::refreshEmptyIcons() void MachineStatus::refreshIcons() { + /* Always show record/play statuses of cassette even if icon updates are disabled, since it's important to indicate play/record modes. */ + if (cassette_enable && cassette) { + d->cassette.setRecord(!!cassette->save); + d->cassette.setPlay(!cassette->save); + } + /* Check if icons should show activity. */ if (!update_icons) return; + if (cassette_enable) { + d->cassette.setWriteActive(machine_status.cassette.write_active); + d->cassette.setActive(machine_status.cassette.active); + } + for (size_t i = 0; i < FDD_NUM; ++i) { d->fdd[i].setActive(machine_status.fdd[i].active); d->fdd[i].setWriteActive(machine_status.fdd[i].write_active); @@ -506,6 +563,8 @@ MachineStatus::refreshIcons() for (size_t i = 0; i < CDROM_NUM; ++i) { d->cdrom[i].setActive(machine_status.cdrom[i].active); d->cdrom[i].setWriteActive(machine_status.cdrom[i].write_active); + d->cdrom[i].setPlay(cdrom_is_playing(i)); + d->cdrom[i].setPause(cdrom_is_paused(i)); if (machine_status.cdrom[i].active) { ui_sb_update_icon(SB_CDROM | i, 0); } diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 5526eee37c0..9d55ba7caa7 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -100,6 +100,7 @@ extern int qt_nvr_save(void); extern void exit_pause(void); bool cpu_thread_running = false; +bool fast_forward = false; } #include @@ -452,7 +453,7 @@ main_thread_fn() #endif drawits += static_cast(new_time - old_time); old_time = new_time; - if (drawits > 0 && !dopause) { + if ((drawits > 0 || fast_forward) && !dopause) { /* Yes, so run frames now. */ do { #ifdef USE_INSTRUMENT @@ -478,8 +479,9 @@ main_thread_fn() } drawits -= force_10ms ? 10 : 1; - if (drawits > 50) + if (drawits > 50 || fast_forward) drawits = 0; + } while (drawits > 0); } else { /* Just so we dont overload the host OS. */ @@ -889,6 +891,7 @@ main(int argc, char *argv[]) QObject::connect(&discordupdate, &QTimer::timeout, &app, [] { discord_run_callbacks(); }); + discordupdate.setInterval(1000); if (enable_discord) discordupdate.start(1000); } diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 083f0761aa1..229e9f788df 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -65,6 +65,7 @@ extern int qt_nvr_save(void); #endif extern bool cpu_thread_running; +extern bool fast_forward; }; #include @@ -164,6 +165,8 @@ keyb_filter(BMessage *message, BHandler **target, BMessageFilter *filter) static BMessageFilter *filter; #endif +extern int cpu_force_interpreter; + extern void qt_mouse_capture(int); extern "C" void qt_blit(int x, int y, int w, int h, int monitor_index); @@ -236,20 +239,26 @@ MainWindow::MainWindow(QWidget *parent) QTimer *ledKeyboardTimer = new QTimer(this); ledKeyboardTimer->setTimerType(Qt::CoarseTimer); - ledKeyboardTimer->setInterval(1); + ledKeyboardTimer->setInterval(20); connect(ledKeyboardTimer, &QTimer::timeout, this, [this]() { + uint8_t prev_caps = 255, prev_num = 255, prev_scroll = 255, prev_kana = 255; uint8_t caps, num, scroll, kana; keyboard_get_states(&caps, &num, &scroll, &kana); - if (num_label->isVisible()) + if (num_label->isVisible() && prev_num != num) num_label->setPixmap(num ? this->num_icon.pixmap(QSize(16, 16)) : this->num_icon_off.pixmap(QSize(16, 16))); - if (caps_label->isVisible()) + if (caps_label->isVisible() && prev_caps != caps) caps_label->setPixmap(caps ? this->caps_icon.pixmap(QSize(16, 16)) : this->caps_icon_off.pixmap(QSize(16, 16))); - if (scroll_label->isVisible()) + if (scroll_label->isVisible() && prev_scroll != scroll) scroll_label->setPixmap(scroll ? this->scroll_icon.pixmap(QSize(16, 16)) : this->scroll_icon_off.pixmap(QSize(16, 16))); - if (kana_label->isVisible()) + if (kana_label->isVisible() && prev_kana != kana) kana_label->setPixmap(kana ? this->kana_icon.pixmap(QSize(16, 16)) : this->kana_icon_off.pixmap(QSize(16, 16))); + + prev_caps = caps; + prev_num = num; + prev_scroll = scroll; + prev_kana = kana; }); ledKeyboardTimer->start(); @@ -278,8 +287,24 @@ MainWindow::MainWindow(QWidget *parent) vmname.truncate(vmname.size() - 1); this->setWindowTitle(QString("%1 - %2 %3").arg(vmname, EMU_NAME, EMU_VERSION_FULL)); + connect(this, &MainWindow::forceInterpretationCompleted, this, [this]() { + const auto fi_icon = cpu_force_interpreter ? QIcon(":/menuicons/qt/icons/recompiler.ico") : + QIcon(":/menuicons/qt/icons/interpreter.ico"); + const auto tooltip_text = cpu_force_interpreter ? QString(tr("Allow recompilation")) : + QString(tr("Force interpretation")); + const auto menu_text = cpu_force_interpreter ? QString(tr("&Allow recompilation")) : + QString(tr("&Force interpretation")); + + ui->actionForce_interpretation->setIcon(fi_icon); + ui->actionForce_interpretation->setToolTip(tooltip_text); + ui->actionForce_interpretation->setText(menu_text); + ui->actionForce_interpretation->setChecked(cpu_force_interpreter); + ui->actionForce_interpretation->setEnabled(cpu_use_dynarec); + }); + connect(this, &MainWindow::hardResetCompleted, this, [this]() { ui->actionMCA_devices->setVisible(machine_has_bus(machine, MACHINE_BUS_MCA)); + ui_update_force_interpreter(); num_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD)); scroll_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD)); caps_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD)); @@ -762,10 +787,6 @@ MainWindow::MainWindow(QWidget *parent) ui->actionUpdate_mouse_every_CPU_frame->setChecked(true); } -#ifdef Q_OS_MACOS - ui->actionCtrl_Alt_Del->setShortcutVisibleInContextMenu(true); - ui->actionTake_screenshot->setShortcutVisibleInContextMenu(true); -#endif if (!vnc_enabled) video_setblit(qt_blit); @@ -793,10 +814,6 @@ MainWindow::MainWindow(QWidget *parent) mtr_stop(); mtr_shutdown(); }; -# ifdef Q_OS_MACOS - ui->actionBegin_trace->setShortcutVisibleInContextMenu(true); - ui->actionEnd_trace->setShortcutVisibleInContextMenu(true); -# endif static bool trace = false; connect(ui->actionBegin_trace, &QAction::triggered, this, [this] { if (trace) @@ -968,6 +985,12 @@ MainWindow::closeEvent(QCloseEvent *event) event->accept(); } +void +ui_update_force_interpreter() +{ + emit main_window->forceInterpretationCompleted(); +} + void MainWindow::updateShortcuts() { @@ -986,6 +1009,7 @@ MainWindow::updateShortcuts() ui->actionHard_Reset->setShortcut(QKeySequence()); ui->actionPause->setShortcut(QKeySequence()); ui->actionMute_Unmute->setShortcut(QKeySequence()); + ui->actionForce_interpretation->setShortcut(QKeySequence()); int accID; QKeySequence seq; @@ -994,6 +1018,18 @@ MainWindow::updateShortcuts() seq = QKeySequence::fromString(acc_keys[accID].seq); ui->actionTake_screenshot->setShortcut(seq); + accID = FindAccelerator("raw_screenshot"); + seq = QKeySequence::fromString(acc_keys[accID].seq); + ui->actionTake_raw_screenshot->setShortcut(seq); + + accID = FindAccelerator("copy_screenshot"); + seq = QKeySequence::fromString(acc_keys[accID].seq); + ui->actionCopy_screenshot->setShortcut(seq); + + accID = FindAccelerator("copy_raw_screenshot"); + seq = QKeySequence::fromString(acc_keys[accID].seq); + ui->actionCopy_raw_screenshot->setShortcut(seq); + accID = FindAccelerator("send_ctrl_alt_del"); seq = QKeySequence::fromString(acc_keys[accID].seq); ui->actionCtrl_Alt_Del->setShortcut(seq); @@ -1006,6 +1042,10 @@ MainWindow::updateShortcuts() seq = QKeySequence::fromString(acc_keys[accID].seq); ui->actionHard_Reset->setShortcut(seq); + accID = FindAccelerator("fast_forward"); + seq = QKeySequence::fromString(acc_keys[accID].seq); + ui->actionFast_forward->setShortcut(seq); + accID = FindAccelerator("fullscreen"); seq = QKeySequence::fromString(acc_keys[accID].seq); ui->actionFullscreen->setShortcut(seq); @@ -1017,6 +1057,10 @@ MainWindow::updateShortcuts() accID = FindAccelerator("mute"); seq = QKeySequence::fromString(acc_keys[accID].seq); ui->actionMute_Unmute->setShortcut(seq); + + accID = FindAccelerator("force_interpretation"); + seq = QKeySequence::fromString(acc_keys[accID].seq); + ui->actionForce_interpretation->setShortcut(seq); } void @@ -1522,6 +1566,18 @@ MainWindow::eventFilter(QObject *receiver, QEvent *event) || (QKeySequence) (ke->key() | ke->modifiers()) == FindAcceleratorSeq("screenshot")) { ui->actionTake_screenshot->trigger(); } + if ((QKeySequence) (ke->key() | (ke->modifiers() & ~Qt::KeypadModifier)) == FindAcceleratorSeq("raw_screenshot") + || (QKeySequence) (ke->key() | ke->modifiers()) == FindAcceleratorSeq("raw_screenshot")) { + ui->actionTake_raw_screenshot->trigger(); + } + if ((QKeySequence) (ke->key() | (ke->modifiers() & ~Qt::KeypadModifier)) == FindAcceleratorSeq("copy_screenshot") + || (QKeySequence) (ke->key() | ke->modifiers()) == FindAcceleratorSeq("copy_screenshot")) { + ui->actionCopy_screenshot->trigger(); + } + if ((QKeySequence) (ke->key() | (ke->modifiers() & ~Qt::KeypadModifier)) == FindAcceleratorSeq("copy_raw_screenshot") + || (QKeySequence) (ke->key() | ke->modifiers()) == FindAcceleratorSeq("copy_raw_screenshot")) { + ui->actionCopy_raw_screenshot->trigger(); + } if ((QKeySequence) (ke->key() | (ke->modifiers() & ~Qt::KeypadModifier)) == FindAcceleratorSeq("fullscreen") || (QKeySequence) (ke->key() | ke->modifiers()) == FindAcceleratorSeq("fullscreen")) { ui->actionFullscreen->trigger(); @@ -1530,6 +1586,10 @@ MainWindow::eventFilter(QObject *receiver, QEvent *event) || (QKeySequence) (ke->key() | ke->modifiers()) == FindAcceleratorSeq("hard_reset")) { ui->actionHard_Reset->trigger(); } + if ((QKeySequence) (ke->key() | (ke->modifiers() & ~Qt::KeypadModifier)) == FindAcceleratorSeq("fast_forward") + || (QKeySequence) (ke->key() | ke->modifiers()) == FindAcceleratorSeq("fast_forward")) { + ui->actionFast_forward->trigger(); + } if ((QKeySequence) (ke->key() | (ke->modifiers() & ~Qt::KeypadModifier)) == FindAcceleratorSeq("send_ctrl_alt_del") || (QKeySequence) (ke->key() | ke->modifiers()) == FindAcceleratorSeq("send_ctrl_alt_del")) { ui->actionCtrl_Alt_Del->trigger(); @@ -1600,6 +1660,7 @@ MainWindow::refreshMediaMenu() status->refresh(ui->statusbar); ui->actionMCA_devices->setVisible(machine_has_bus(machine, MACHINE_BUS_MCA)); ui->actionACPI_Shutdown->setEnabled(!!acpi_enabled); + ui_update_force_interpreter(); num_label->setToolTip(QShortcut::tr("Num Lock")); num_label->setVisible(machine_has_bus(machine, MACHINE_BUS_PS2_PORTS | MACHINE_BUS_AT_KBD)); @@ -1788,6 +1849,13 @@ MainWindow::on_actionInverted_VGA_monitor_triggered() video_toggle_option(ui->actionInverted_VGA_monitor, &invert_display); } +void +MainWindow::on_actionForce_interpretation_triggered() +{ + cpu_force_interpreter ^= 1; + ui_update_force_interpreter(); +} + static void update_scaled_checkboxes(Ui::MainWindow *ui, QAction *selected) { @@ -2100,6 +2168,12 @@ MainWindow::on_actionUpdate_mouse_every_CPU_frame_triggered() config_save(); } +void +MainWindow::on_actionFast_forward_triggered() +{ + fast_forward ^= 1; +} + void MainWindow::on_actionRemember_size_and_position_triggered() { @@ -2234,6 +2308,36 @@ MainWindow::on_actionTake_screenshot_triggered() device_force_redraw(); } +void +MainWindow::on_actionTake_raw_screenshot_triggered() +{ + startblit(); + for (auto &monitor : monitors) + ++monitor.mon_screenshots_raw; + endblit(); + device_force_redraw(); +} + +void +MainWindow::on_actionCopy_screenshot_triggered() +{ + startblit(); + for (auto &monitor : monitors) + ++monitor.mon_screenshots_clipboard; + endblit(); + device_force_redraw(); +} + +void +MainWindow::on_actionCopy_raw_screenshot_triggered() +{ + startblit(); + for (auto &monitor : monitors) + ++monitor.mon_screenshots_raw_clipboard; + endblit(); + device_force_redraw(); +} + void MainWindow::on_actionMute_Unmute_triggered() { diff --git a/src/qt/qt_mainwindow.hpp b/src/qt/qt_mainwindow.hpp index 1a1cf4f2037..2fa2ab3b981 100644 --- a/src/qt/qt_mainwindow.hpp +++ b/src/qt/qt_mainwindow.hpp @@ -58,6 +58,7 @@ class MainWindow : public QMainWindow { void destroyRendererMonitor(int monitor_index); void initRendererMonitorForNonQtThread(int monitor_index); void destroyRendererMonitorForNonQtThread(int monitor_index); + void forceInterpretationCompleted(); void hardResetCompleted(); void setTitle(const QString &title); @@ -79,6 +80,7 @@ public slots: void updateStatusEmptyIcons(); void updateUiPauseState(); private slots: + void on_actionForce_interpretation_triggered(); void on_actionFullscreen_triggered(); void on_actionSettings_triggered(); void on_actionExit_triggered(); @@ -130,12 +132,16 @@ private slots: void on_actionHide_tool_bar_triggered(); void on_actionUpdate_status_bar_icons_triggered(); void on_actionTake_screenshot_triggered(); + void on_actionTake_raw_screenshot_triggered(); + void on_actionCopy_screenshot_triggered(); + void on_actionCopy_raw_screenshot_triggered(); void toggleFullscreenUI(); void on_actionMute_Unmute_triggered(); void on_actionSound_gain_triggered(); void on_actionPreferences_triggered(); void on_actionEnable_Discord_integration_triggered(bool checked); void on_actionRenderer_options_triggered(); + void on_actionFast_forward_triggered(); void refreshMediaMenu(); void showMessage_(int flags, const QString &header, const QString &message, bool richText, std::atomic_bool *done = nullptr); diff --git a/src/qt/qt_mainwindow.ui b/src/qt/qt_mainwindow.ui index 45c4f70ae08..2dead393bbe 100644 --- a/src/qt/qt_mainwindow.ui +++ b/src/qt/qt_mainwindow.ui @@ -78,11 +78,16 @@ + + + + + @@ -103,6 +108,10 @@ + + + + @@ -293,15 +302,27 @@ false + - + + + + + + + :/menuicons/qt/icons/interpreter.ico:/menuicons/qt/icons/interpreter.ico + + + &Force interpretation + + true @@ -342,8 +363,8 @@ &Hard reset - - false + + Hard reset @@ -355,16 +376,7 @@ &Ctrl+Alt+Del - Ctrl+Alt+Del - - - Ctrl+F12 - - - false - - - false + Press Ctrl+Alt+Del @@ -375,8 +387,8 @@ Ctrl+Alt+&Esc - - false + + Press Ctrl+Alt+Esc @@ -387,9 +399,6 @@ &Pause - - false - @@ -405,22 +414,19 @@ :/menuicons/qt/icons/settings.ico:/menuicons/qt/icons/settings.ico - &Settings... + &Settings… + + + Settings… QAction::NoRole - - false - &Fullscreen - - Ctrl+Alt+PgUp - @@ -459,7 +465,7 @@ - Specify &dimensions... + Specify &dimensions… @@ -715,7 +721,7 @@ - &About 86Box... + &About 86Box… QAction::AboutRole @@ -723,7 +729,7 @@ - &Documentation... + &Documentation… @@ -738,11 +744,48 @@ Take s&creenshot - - Ctrl+F11 + + Take screenshot - - false + + + :/menuicons/qt/icons/take_screenshot.ico:/menuicons/qt/icons/take_screenshot.ico + + + + + Take &raw screenshot + + + Take raw screenshot + + + + :/menuicons/qt/icons/take_raw_screenshot.ico:/menuicons/qt/icons/take_raw_screenshot.ico + + + + + C&opy screenshot + + + Copy screenshot + + + + :/menuicons/qt/icons/copy_screenshot.ico:/menuicons/qt/icons/copy_screenshot.ico + + + + + Copy r&aw screenshot + + + Copy raw screenshot + + + + :/menuicons/qt/icons/copy_raw_screenshot.ico:/menuicons/qt/icons/copy_raw_screenshot.ico @@ -752,7 +795,7 @@ - Sound &gain... + Sound &gain… @@ -768,7 +811,7 @@ - &Preferences... + &Preferences… QAction::PreferencesRole @@ -789,9 +832,6 @@ Hide &toolbar - - Hide tool bar - @@ -821,9 +861,6 @@ false - - false - @@ -835,13 +872,10 @@ false - - false - - Renderer &options... + Renderer &options… QAction::NoRole @@ -860,7 +894,7 @@ - &MCA devices... + &MCA devices… @@ -884,12 +918,12 @@ - Open p&rinter tray... + Open p&rinter tray… - Open screenshots &folder... + Open screenshots &folder… @@ -918,7 +952,7 @@ - &CGA composite settings... + &CGA composite settings… @@ -1049,6 +1083,21 @@ &8x + + + true + + + + :/settings/qt/icons/fast_forward.ico:/settings/qt/icons/fast_forward.ico + + + &Fast forward + + + Fast forward + + diff --git a/src/qt/qt_mediamenu.cpp b/src/qt/qt_mediamenu.cpp index 75b2e2b978a..968858dd28e 100644 --- a/src/qt/qt_mediamenu.cpp +++ b/src/qt/qt_mediamenu.cpp @@ -87,10 +87,10 @@ MediaMenu::refresh(QMenu *parentMenu) if (MachineStatus::hasCassette()) { cassetteMenu = parentMenu->addMenu(""); QIcon img_icon = QIcon(":/settings/qt/icons/cassette_image.ico"); - cassetteMenu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, New), tr("&New image..."), [this]() { cassetteNewImage(); }); + cassetteMenu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, New), tr("&New image…"), [this]() { cassetteNewImage(); }); cassetteMenu->addSeparator(); - cassetteMenu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, Browse), tr("&Existing image..."), [this]() { cassetteSelectImage(false); }); - cassetteMenu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, WriteProtectedBrowse), tr("Existing image (&Write-protected)..."), [this]() { cassetteSelectImage(true); }); + cassetteMenu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, Browse), tr("&Existing image…"), [this]() { cassetteSelectImage(false); }); + cassetteMenu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, WriteProtectedBrowse), tr("Existing image (&Write-protected)…"), [this]() { cassetteSelectImage(true); }); cassetteMenu->addSeparator(); for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) { cassetteImageHistoryPos[slot] = cassetteMenu->children().count(); @@ -116,7 +116,7 @@ MediaMenu::refresh(QMenu *parentMenu) for (int i = 0; i < 2; i++) { auto *menu = parentMenu->addMenu(""); QIcon img_icon = QIcon(":/settings/qt/icons/cartridge_image.ico"); - menu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, Browse), tr("&Image..."), [this, i]() { cartridgeSelectImage(i); }); + menu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, Browse), tr("&Image…"), [this, i]() { cartridgeSelectImage(i); }); menu->addSeparator(); for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) { cartridgeImageHistoryPos[slot] = menu->children().count(); @@ -134,10 +134,10 @@ MediaMenu::refresh(QMenu *parentMenu) MachineStatus::iterateFDD([this, parentMenu](int i) { auto *menu = parentMenu->addMenu(""); QIcon img_icon = fdd_is_525(i) ? QIcon(":/settings/qt/icons/floppy_525_image.ico") : QIcon(":/settings/qt/icons/floppy_35_image.ico"); - menu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, New), tr("&New image..."), [this, i]() { floppyNewImage(i); }); + menu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, New), tr("&New image…"), [this, i]() { floppyNewImage(i); }); menu->addSeparator(); - menu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, Browse), tr("&Existing image..."), [this, i]() { floppySelectImage(i, false); }); - menu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, WriteProtectedBrowse), tr("Existing image (&Write-protected)..."), [this, i]() { floppySelectImage(i, true); }); + menu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, Browse), tr("&Existing image…"), [this, i]() { floppySelectImage(i, false); }); + menu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, WriteProtectedBrowse), tr("Existing image (&Write-protected)…"), [this, i]() { floppySelectImage(i, true); }); menu->addSeparator(); for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) { floppyImageHistoryPos[slot] = menu->children().count(); @@ -145,7 +145,7 @@ MediaMenu::refresh(QMenu *parentMenu) } menu->addSeparator(); floppyExportPos = menu->children().count(); - menu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, Export), tr("E&xport to 86F..."), [this, i]() { floppyExportTo86f(i); }); + menu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, Export), tr("E&xport to 86F…"), [this, i]() { floppyExportTo86f(i); }); menu->addSeparator(); floppyEjectPos = menu->children().count(); menu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, Eject), tr("E&ject"), [this, i]() { floppyEject(i); }); @@ -159,8 +159,8 @@ MediaMenu::refresh(QMenu *parentMenu) cdromMutePos = menu->children().count(); menu->addAction(QIcon(":/settings/qt/icons/cdrom_mute.ico"), tr("&Mute"), [this, i]() { cdromMute(i); })->setCheckable(true); menu->addSeparator(); - menu->addAction(getIconWithIndicator(QIcon(":/settings/qt/icons/cdrom_image.ico"), pixmap_size, QIcon::Normal, Browse), tr("&Image..."), [this, i]() { cdromMount(i, 0, nullptr); })->setCheckable(false); - menu->addAction(getIconWithIndicator(QIcon(":/settings/qt/icons/cdrom_folder.ico"), pixmap_size, QIcon::Normal, Browse), tr("&Folder..."), [this, i]() { cdromMount(i, 1, nullptr); })->setCheckable(false); + menu->addAction(getIconWithIndicator(QIcon(":/settings/qt/icons/cdrom_image.ico"), pixmap_size, QIcon::Normal, Browse), tr("&Image…"), [this, i]() { cdromMount(i, 0, nullptr); })->setCheckable(false); + menu->addAction(getIconWithIndicator(QIcon(":/settings/qt/icons/cdrom_folder.ico"), pixmap_size, QIcon::Normal, Browse), tr("&Folder…"), [this, i]() { cdromMount(i, 1, nullptr); })->setCheckable(false); menu->addSeparator(); for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) { cdromImageHistoryPos[slot] = menu->children().count(); @@ -187,10 +187,10 @@ MediaMenu::refresh(QMenu *parentMenu) MachineStatus::iterateRDisk([this, parentMenu](int i) { auto *menu = parentMenu->addMenu(""); QIcon img_icon = QIcon(":/settings/qt/icons/rdisk_image.ico"); - menu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, New), tr("&New image..."), [this, i]() { rdiskNewImage(i); }); + menu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, New), tr("&New image…"), [this, i]() { rdiskNewImage(i); }); menu->addSeparator(); - menu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, Browse), tr("&Existing image..."), [this, i]() { rdiskSelectImage(i, false); }); - menu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, WriteProtectedBrowse), tr("Existing image (&Write-protected)..."), [this, i]() { rdiskSelectImage(i, true); }); + menu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, Browse), tr("&Existing image…"), [this, i]() { rdiskSelectImage(i, false); }); + menu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, WriteProtectedBrowse), tr("Existing image (&Write-protected)…"), [this, i]() { rdiskSelectImage(i, true); }); menu->addSeparator(); for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) { rdiskImageHistoryPos[slot] = menu->children().count(); @@ -207,10 +207,10 @@ MediaMenu::refresh(QMenu *parentMenu) MachineStatus::iterateMO([this, parentMenu](int i) { auto *menu = parentMenu->addMenu(""); QIcon img_icon = QIcon(":/settings/qt/icons/mo_image.ico"); - menu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, New), tr("&New image..."), [this, i]() { moNewImage(i); }); + menu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, New), tr("&New image…"), [this, i]() { moNewImage(i); }); menu->addSeparator(); - menu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, Browse), tr("&Existing image..."), [this, i]() { moSelectImage(i, false); }); - menu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, WriteProtectedBrowse), tr("Existing image (&Write-protected)..."), [this, i]() { moSelectImage(i, true); }); + menu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, Browse), tr("&Existing image…"), [this, i]() { moSelectImage(i, false); }); + menu->addAction(getIconWithIndicator(img_icon, pixmap_size, QIcon::Normal, WriteProtectedBrowse), tr("Existing image (&Write-protected)…"), [this, i]() { moSelectImage(i, true); }); menu->addSeparator(); for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) { moImageHistoryPos[slot] = menu->children().count(); @@ -238,7 +238,7 @@ MediaMenu::refresh(QMenu *parentMenu) void MediaMenu::cassetteNewImage() { - auto filename = QFileDialog::getSaveFileName(parentWidget, tr("Create...")); + auto filename = QFileDialog::getSaveFileName(parentWidget, tr("Create…")); QFileInfo fileinfo(filename); if (fileinfo.suffix().isEmpty()) { filename.append(".cas"); @@ -292,7 +292,7 @@ MediaMenu::cassetteMount(const QString &filename, bool wp) pc_cas_set_fname(cassette, cassette_fname); } - ui_sb_update_icon_state(SB_CASSETTE, filename.isEmpty() ? 1 : 0); + ui_sb_update_icon_state(SB_CASSETTE, cassette->fname == nullptr); ui_sb_update_icon_wp(SB_CASSETTE, cassette_ui_writeprot); mhm.addImageToHistory(0, ui::MediaType::Cassette, previous_image.filePath(), filename); cassetteUpdateMenu(); @@ -352,7 +352,7 @@ MediaMenu::cartridgeMount(int i, const QString &filename) QByteArray filenameBytes = filename.toUtf8(); cart_load(i, filenameBytes.data()); - ui_sb_update_icon_state(SB_CARTRIDGE | i, filename.isEmpty() ? 1 : 0); + ui_sb_update_icon_state(SB_CARTRIDGE | i, cart_fns[i][0] == 0); mhm.addImageToHistory(i, ui::MediaType::Cartridge, previous_image.filePath(), filename); cartridgeUpdateMenu(i); ui_sb_update_tip(SB_CARTRIDGE | i); @@ -468,7 +468,7 @@ MediaMenu::floppyMount(int i, const QString &filename, bool wp) mhm.addImageToHistory(i, ui::MediaType::Floppy, previous_image.filePath(), QString(filenameBytes)); } else mhm.addImageToHistory(i, ui::MediaType::Floppy, previous_image.filePath(), filename); - ui_sb_update_icon_state(SB_FLOPPY | i, filename.isEmpty() ? 1 : 0); + ui_sb_update_icon_state(SB_FLOPPY | i, drive_empty[i]); ui_sb_update_icon_wp(SB_FLOPPY | i, ui_writeprot[i]); floppyUpdateMenu(i); ui_sb_update_tip(SB_FLOPPY | i); @@ -596,7 +596,7 @@ MediaMenu::cdromMount(int i, int dir, const QString &arg) else { filename = QFileDialog::getOpenFileName(parentWidget, QString(), QString(), - tr("CD-ROM images") % util::DlgFilter({ "iso", "cue", "mds" }) % tr("All files") % util::DlgFilter({ "*" }, true)); + tr("CD-ROM images") % util::DlgFilter({ "iso", "cue", "mds", "mdx" }) % tr("All files") % util::DlgFilter({ "*" }, true)); } if (filename.isEmpty()) @@ -668,7 +668,7 @@ MediaMenu::updateImageHistory(int index, int slot, ui::MediaType type) else fi.setFile(fn); if (!fi.fileName().isEmpty() && (fn.left(5) == "wp://")) { - menu_item_name = fi.fileName().isEmpty() ? tr("Reload previous image") : fn.right(fn.length() - 5); + menu_item_name = fi.fileName().isEmpty() ? tr("Reload previous image") : "🔒 " + fn.right(fn.length() - 5); imageHistoryUpdatePos->setIcon(getIconWithIndicator(menu_icon, pixmap_size, QIcon::Normal, WriteProtected)); } else { menu_item_name = fi.fileName().isEmpty() ? tr("Reload previous image") : fn; @@ -696,7 +696,7 @@ MediaMenu::updateImageHistory(int index, int slot, ui::MediaType type) else fi.setFile(fn); if (!fi.fileName().isEmpty() && (fn.left(5) == "wp://")) { - menu_item_name = fi.fileName().isEmpty() ? tr("Reload previous image") : fn.right(fn.length() - 5); + menu_item_name = fi.fileName().isEmpty() ? tr("Reload previous image") : "🔒 " + fn.right(fn.length() - 5); imageHistoryUpdatePos->setIcon(getIconWithIndicator(menu_icon, pixmap_size, QIcon::Normal, WriteProtected)); } else { menu_item_name = fi.fileName().isEmpty() ? tr("Reload previous image") : fn; @@ -735,7 +735,7 @@ MediaMenu::updateImageHistory(int index, int slot, ui::MediaType type) else fi.setFile(fn); if (!fi.fileName().isEmpty() && (fn.left(5) == "wp://")) { - menu_item_name = fi.fileName().isEmpty() ? tr("Reload previous image") : fn.right(fn.length() - 5); + menu_item_name = fi.fileName().isEmpty() ? tr("Reload previous image") : "🔒 " + fn.right(fn.length() - 5); imageHistoryUpdatePos->setIcon(getIconWithIndicator(menu_icon, pixmap_size, QIcon::Normal, WriteProtected)); } else { menu_item_name = fi.fileName().isEmpty() ? tr("Reload previous image") : fn; @@ -754,7 +754,7 @@ MediaMenu::updateImageHistory(int index, int slot, ui::MediaType type) else fi.setFile(fn); if (!fi.fileName().isEmpty() && (fn.left(5) == "wp://")) { - menu_item_name = fi.fileName().isEmpty() ? tr("Reload previous image") : fn.right(fn.length() - 5); + menu_item_name = fi.fileName().isEmpty() ? tr("Reload previous image") : "🔒 " + fn.right(fn.length() - 5); imageHistoryUpdatePos->setIcon(getIconWithIndicator(menu_icon, pixmap_size, QIcon::Normal, WriteProtected)); } else { menu_item_name = fi.fileName().isEmpty() ? tr("Reload previous image") : fn; @@ -902,7 +902,7 @@ MediaMenu::rdiskMount(int i, const QString &filename, bool wp) } mhm.addImageToHistory(i, ui::MediaType::RDisk, rdisk_drives[i].prev_image_path, rdisk_drives[i].image_path); - ui_sb_update_icon_state(SB_RDISK | i, filename.isEmpty() ? 1 : 0); + ui_sb_update_icon_state(SB_RDISK | i, dev->drv->fp == NULL); ui_sb_update_icon_wp(SB_RDISK | i, wp); rdiskUpdateMenu(i); ui_sb_update_tip(SB_RDISK | i); @@ -1082,7 +1082,7 @@ MediaMenu::moMount(int i, const QString &filename, bool wp) } mhm.addImageToHistory(i, ui::MediaType::Mo, mo_drives[i].prev_image_path, mo_drives[i].image_path); - ui_sb_update_icon_state(SB_MO | i, filename.isEmpty() ? 1 : 0); + ui_sb_update_icon_state(SB_MO | i, dev->drv->fp == nullptr); moUpdateMenu(i); ui_sb_update_tip(SB_MO | i); @@ -1160,9 +1160,10 @@ MediaMenu::nicUpdateMenu(int i) if (!netMenus.contains(i)) return; - QString netType = tr("Null Driver"); + QString netType; switch (net_cards_conf[i].net_type) { default: + netType = tr("Null Driver"); break; case NET_TYPE_SLIRP: netType = "SLiRP"; @@ -1176,11 +1177,11 @@ MediaMenu::nicUpdateMenu(int i) case NET_TYPE_TAP: netType = "TAP"; break; - case NET_TYPE_NMSWITCH: - netType = "Local Switch"; + case NET_TYPE_NLSWITCH: + netType = tr("Local Switch"); break; case NET_TYPE_NRSWITCH: - netType = "Remote Switch"; + netType = tr("Remote Switch"); break; } diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index 8e01bfe6c1c..788a7474462 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -26,6 +26,7 @@ extern MainWindow *main_window; #include #include #include +#include #include #include #include @@ -599,7 +600,7 @@ load_texture(const char *f, struct shader_texture *tex) const GLubyte *rgb = img.constBits(); - int bpp = 4; + int bpp = 3; GLubyte *data = (GLubyte *) malloc((size_t) width * height * bpp); @@ -610,7 +611,6 @@ load_texture(const char *f, struct shader_texture *tex) data[(y * width + x) * bpp + 0] = rgb[(Y * width + x) * 3 + 0]; data[(y * width + x) * bpp + 1] = rgb[(Y * width + x) * 3 + 1]; data[(y * width + x) * bpp + 2] = rgb[(Y * width + x) * 3 + 2]; - data[(y * width + x) * bpp + 3] = rgb[(Y * width + x) * 3 + 3]; } } @@ -1147,6 +1147,8 @@ OpenGLRenderer::finalize() isFinalized = true; } +extern void take_screenshot_clipboard_monitor(int sx, int sy, int sw, int sh, int i); + void OpenGLRenderer::onBlit(int buf_idx, int x, int y, int w, int h) { @@ -1184,6 +1186,10 @@ OpenGLRenderer::onBlit(int buf_idx, int x, int y, int w, int h) if (video_framerate == -1) render(); + + if (monitors[r_monitor_index].mon_screenshots_raw_clipboard) { + take_screenshot_clipboard_monitor(x, y, w, h, r_monitor_index); + } } std::vector> @@ -1725,6 +1731,20 @@ OpenGLRenderer::render() monitors[r_monitor_index].mon_screenshots--; free(rgb); } + if (monitors[r_monitor_index].mon_screenshots_clipboard) { + int width = destination.width(), height = destination.height(); + + unsigned char *rgb = (unsigned char *) calloc(1, (size_t) width * height * 4); + + glw.glFinish(); + glw.glReadPixels(window_rect.x, window_rect.y, width, height, GL_RGB, GL_UNSIGNED_BYTE, rgb); + + QImage image((uchar*)rgb, width, height, width * 3, QImage::Format_RGB888); + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setImage(image.mirrored(false, true), QClipboard::Clipboard); + monitors[r_monitor_index].mon_screenshots_clipboard--; + free(rgb); + } glw.glDisable(GL_FRAMEBUFFER_SRGB); diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index a042d8b7d16..3ecff875a0f 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -30,8 +30,11 @@ #include +#include +#include #include #include +#include #include #include #include @@ -273,7 +276,7 @@ plat_getcwd(char *bufp, int max) strncpy(bufp, exe_path, max); # else CharPointer(bufp, max) = QDir::homePath().toUtf8(); - path_append_filename(bufp, bufp, "Library/86Box"); + path_append_filename(bufp, bufp, "Library/" EMU_NAME); # endif #else CharPointer(bufp, max) = QDir::currentPath().toUtf8(); @@ -749,6 +752,16 @@ plat_chdir(char *path) return QDir::setCurrent(QString(path)) ? 0 : -1; } +#ifdef _WIN32 +void plat_get_system_directory(char *outbuf) +{ + wchar_t wc[512]; + GetSystemWindowsDirectoryW(wc, 512); + QString str = QString::fromWCharArray(wc); + strcpy(outbuf, str.toUtf8()); +} +#endif + void plat_get_global_config_dir(char *outbuf, const size_t len) { @@ -828,10 +841,10 @@ plat_init_rom_paths(void) for (auto &path : paths) { #ifdef __APPLE__ - rom_add_path(QDir(path).filePath("net.86Box.86Box/roms").toUtf8().constData()); - rom_add_path(QDir(path).filePath("86Box/roms").toUtf8().constData()); + rom_add_path(QDir(path).filePath("net." EMU_NAME "." EMU_NAME "/roms").toUtf8().constData()); + rom_add_path(QDir(path).filePath(EMU_NAME "/roms").toUtf8().constData()); #else - rom_add_path(QDir(path).filePath("86Box/roms").toUtf8().constData()); + rom_add_path(QDir(path).filePath(EMU_NAME "/roms").toUtf8().constData()); #endif } } @@ -852,10 +865,10 @@ plat_init_asset_paths(void) for (auto &path : paths) { #ifdef __APPLE__ - asset_add_path(QDir(path).filePath("net.86Box.86Box/assets").toUtf8().constData()); - asset_add_path(QDir(path).filePath("86Box/assets").toUtf8().constData()); + asset_add_path(QDir(path).filePath("net." EMU_NAME "." EMU_NAME "/assets").toUtf8().constData()); + asset_add_path(QDir(path).filePath(EMU_NAME "/assets").toUtf8().constData()); #else - asset_add_path(QDir(path).filePath("86Box/assets").toUtf8().constData()); + asset_add_path(QDir(path).filePath(EMU_NAME "/assets").toUtf8().constData()); #endif } } @@ -978,3 +991,37 @@ plat_break(void) raise(SIGTRAP); #endif } + +static unsigned char *rgb_ = NULL; +static int width_ = 0; +static int height_ = 0; +static volatile int waiting = 0; + +static void +send_to_clipboard(void) +{ + unsigned char *rgb = (unsigned char *) calloc(1, height_ * width_ * 4); + memcpy(rgb, rgb_, height_ * width_ * 3); + QImage image(rgb, width_, height_, width_ * 3, QImage::Format_RGB888); + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setImage(image, QClipboard::Clipboard); + free(rgb); + waiting = 0; +} + +void +plat_send_to_clipboard(unsigned char *rgb, int width, int height) +{ + rgb_ = rgb; + width_ = width; + height_ = height; + waiting = 1; + + QTimer::singleShot(0, main_window, &send_to_clipboard); + while (waiting) + ; + + height_ = 0; + width_ = 0; + rgb_ = NULL; +} diff --git a/src/qt/qt_progsettings.cpp b/src/qt/qt_progsettings.cpp index 268cec8945b..62b63bbcc14 100644 --- a/src/qt/qt_progsettings.cpp +++ b/src/qt/qt_progsettings.cpp @@ -47,11 +47,13 @@ QTranslator *ProgSettings::qtTranslator = nullptr; QVector> ProgSettings::languages = { { "system", "(System Default)" }, + { "ca-ES", "Catalan (Spain)" }, { "zh-CN", "Chinese (Simplified)" }, { "zh-TW", "Chinese (Traditional)" }, { "hr-HR", "Croatian (Croatia)" }, { "cs-CZ", "Czech (Czech Republic)" }, { "de-DE", "German (Germany)" }, + { "el-GR", "Greek (Greece)" }, { "en-GB", "English (United Kingdom)" }, { "en-US", "English (United States)" }, { "fi-FI", "Finnish (Finland)" }, diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index 41d17d8971b..99a6bf649d3 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -33,6 +33,9 @@ #include #include +#include +#include + #include #include #ifdef TOUCH_PR @@ -66,9 +69,12 @@ # include #endif +#include + extern "C" { #include <86box/86box.h> #include <86box/config.h> +#include <86box/path.h> #include <86box/plat.h> #include <86box/video.h> #include <86box/mouse.h> @@ -87,6 +93,8 @@ extern MainWindow *main_window; HWND rw_hwnd; #endif +static unsigned char *screenshot_rgb = NULL; + RendererStack::RendererStack(QWidget *parent, int monitor_index) : QWidget(parent) , boxLayout(new QBoxLayout(QBoxLayout::TopToBottom, this)) @@ -158,12 +166,20 @@ RendererStack::RendererStack(QWidget *parent, int monitor_index) if (monitor_index == 0) mouse_set_raw(raw); + + screenshot_rgb = (unsigned char *) calloc(1, (size_t) 2048 * 2048 * 4); } RendererStack::~RendererStack() { + if (screenshot_rgb != NULL) { + free(screenshot_rgb); + screenshot_rgb = NULL; + } + while (QApplication::overrideCursor()) QApplication::restoreOverrideCursor(); + delete ui; } @@ -372,11 +388,7 @@ RendererStack::createRenderer(Renderer renderer) auto sw = new SoftwareRenderer(this); rendererWindow = sw; connect(this, &RendererStack::blitToRenderer, sw, &SoftwareRenderer::onBlit, Qt::QueuedConnection); -#ifdef __HAIKU__ current.reset(sw); -#else - current.reset(this->createWindowContainer(sw)); -#endif } break; case Renderer::OpenGL3: @@ -460,6 +472,32 @@ RendererStack::createRenderer(Renderer renderer) } } +uint32_t *screenshot_buf = NULL; + +void +take_screenshot_clipboard_monitor(int sx, int sy, int sw, int sh, int i) +{ + uint32_t temp = 0x00000000; + + for (int y = 0; y < sh; ++y) { + for (int x = 0; x < sw; ++x) { + if (screenshot_buf == NULL) + memset(&(screenshot_rgb[(y * sw * 3) + (x * 3)]), 0x00, 3); + else { + temp = screenshot_buf[((sy + y) * 2048) + sx + x]; + screenshot_rgb[(y * sw * 3) + (x * 3)] = (temp >> 16) & 0xff; + screenshot_rgb[(y * sw * 3) + (x * 3) + 1] = (temp >> 8) & 0xff; + screenshot_rgb[(y * sw * 3) + (x * 3) + 2] = temp & 0xff; + } + } + } + + QImage image(screenshot_rgb, sw, sh, sw * 3, QImage::Format_RGB888); + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setImage(image, QClipboard::Clipboard); + monitors[i].mon_screenshots_raw_clipboard--; +} + // called from blitter thread void RendererStack::blit(int x, int y, int w, int h) @@ -478,10 +516,11 @@ RendererStack::blit(int x, int y, int w, int h) video_copy(scanline, &(monitors[m_monitor_index].target_buffer->line[y1][x]), w * 4); } - if (monitors[m_monitor_index].mon_screenshots && !rendererTakesScreenshots) { + if (monitors[m_monitor_index].mon_screenshots_raw) { video_screenshot_monitor((uint32_t *) imagebits, x, y, 2048, m_monitor_index); } video_blit_complete_monitor(m_monitor_index); + screenshot_buf = (uint32_t *) imagebits; emit blitToRenderer(currentBuf, sx, sy, sw, sh); currentBuf = (currentBuf + 1) % imagebufs.size(); } diff --git a/src/qt/qt_settings_bus_tracking.cpp b/src/qt/qt_settings_bus_tracking.cpp index aee57da1bdb..77865be7256 100644 --- a/src/qt/qt_settings_bus_tracking.cpp +++ b/src/qt/qt_settings_bus_tracking.cpp @@ -19,9 +19,13 @@ #include #include +extern "C" { +#include "86box/86box.h" #include "86box/hdd.h" #include "86box/scsi.h" #include "86box/cdrom.h" +} + #include "qt_settings_bus_tracking.hpp" SettingsBusTracking::SettingsBusTracking() diff --git a/src/qt/qt_settingsdisplay.cpp b/src/qt/qt_settingsdisplay.cpp index 6df4d5edc51..d5fbe77d5a1 100644 --- a/src/qt/qt_settingsdisplay.cpp +++ b/src/qt/qt_settingsdisplay.cpp @@ -106,6 +106,9 @@ SettingsDisplay::onCurrentMachineChanged(int machineId) } if (video_card_available(c) && device_is_valid(video_dev, machineId)) { + if (c == 1 && machine_get_vid_device(machineId)) { + name += QString(" (%1)").arg(DeviceConfig::DeviceName(machine_get_vid_device(machineId), machine_get_vid_device(machineId)->internal_name, 0)); + } int row = Models::AddEntry(model, name, c); if (c == curVideoCard) { selectedRow = row - removeRows; diff --git a/src/qt/qt_settingsdisplay.ui b/src/qt/qt_settingsdisplay.ui index 5ab71f4c0a9..71f10331966 100644 --- a/src/qt/qt_settingsdisplay.ui +++ b/src/qt/qt_settingsdisplay.ui @@ -184,7 +184,7 @@ - Export... + Export… @@ -198,7 +198,7 @@ - Custom... + Custom… diff --git a/src/qt/qt_settingsfloppycdrom.cpp b/src/qt/qt_settingsfloppycdrom.cpp index 8fcad3f210e..d896614d84f 100644 --- a/src/qt/qt_settingsfloppycdrom.cpp +++ b/src/qt/qt_settingsfloppycdrom.cpp @@ -149,7 +149,7 @@ SettingsFloppyCDROM::SettingsFloppyCDROM(QWidget *parent) #ifndef DISABLE_FDD_AUDIO // Get the profile name from the configuration system - const char *name = fdd_audio_get_profile_internal_name(prof); + const char *name = fdd_audio_get_profile_name(prof); if (name) { profName = QString(name); } else { @@ -449,7 +449,7 @@ SettingsFloppyCDROM::on_comboBoxFloppyAudio_activated(int) #ifndef DISABLE_FDD_AUDIO // Get the profile name from the configuration system - const char *name = fdd_audio_get_profile_internal_name(prof); + const char *name = fdd_audio_get_profile_name(prof); if (name) { profName = name; } else { diff --git a/src/qt/qt_settingsharddisks.cpp b/src/qt/qt_settingsharddisks.cpp index 0f12c8e6f65..849c3430520 100644 --- a/src/qt/qt_settingsharddisks.cpp +++ b/src/qt/qt_settingsharddisks.cpp @@ -20,6 +20,7 @@ extern "C" { #include <86box/86box.h> #include <86box/hdd.h> +#include <86box/hdd_audio.h> } #include @@ -36,6 +37,7 @@ const int ColumnHeads = 3; const int ColumnSectors = 4; const int ColumnSize = 5; const int ColumnSpeed = 6; +const int ColumnAudio = 7; const int DataBus = Qt::UserRole; const int DataBusChannel = Qt::UserRole + 1; @@ -103,6 +105,11 @@ addRow(QAbstractItemModel *model, hard_disk_t *hd) auto speedIndex = model->index(row, ColumnSpeed); model->setData(speedIndex, QObject::tr(hdd_preset_getname(hd->speed_preset))); model->setData(speedIndex, hd->speed_preset, Qt::UserRole); + + auto audioIndex = model->index(row, ColumnAudio); + const char *audioName = hdd_audio_get_profile_name(hd->audio_profile); + model->setData(audioIndex, audioName ? QObject::tr(audioName) : QObject::tr("None")); + model->setData(audioIndex, hd->audio_profile, Qt::UserRole); } SettingsHarddisks::SettingsHarddisks(QWidget *parent) @@ -113,7 +120,7 @@ SettingsHarddisks::SettingsHarddisks(QWidget *parent) hard_disk_icon = QIcon(":/settings/qt/icons/hard_disk.ico"); - QAbstractItemModel *model = new QStandardItemModel(0, 7, this); + QAbstractItemModel *model = new QStandardItemModel(0, 8, this); model->setHeaderData(ColumnBus, Qt::Horizontal, tr("Bus")); model->setHeaderData(ColumnFilename, Qt::Horizontal, tr("File")); model->setHeaderData(ColumnCylinders, Qt::Horizontal, tr("C")); @@ -121,6 +128,7 @@ SettingsHarddisks::SettingsHarddisks(QWidget *parent) model->setHeaderData(ColumnSectors, Qt::Horizontal, tr("S")); model->setHeaderData(ColumnSize, Qt::Horizontal, tr("MiB")); model->setHeaderData(ColumnSpeed, Qt::Horizontal, tr("Model")); + model->setHeaderData(ColumnAudio, Qt::Horizontal, tr("Audio")); ui->tableView->setModel(model); for (int i = 0; i < HDD_NUM; i++) { @@ -139,6 +147,7 @@ SettingsHarddisks::SettingsHarddisks(QWidget *parent) onTableRowChanged(QModelIndex()); Harddrives::populateBuses(ui->comboBoxBus->model()); + on_comboBoxBus_currentIndexChanged(0); } @@ -162,6 +171,7 @@ SettingsHarddisks::save() hdd[i].hpc = idx.siblingAtColumn(ColumnHeads).data().toUInt(); hdd[i].spt = idx.siblingAtColumn(ColumnSectors).data().toUInt(); hdd[i].speed_preset = idx.siblingAtColumn(ColumnSpeed).data(Qt::UserRole).toUInt(); + hdd[i].audio_profile = idx.siblingAtColumn(ColumnAudio).data(Qt::UserRole).toUInt(); QByteArray fileName = idx.siblingAtColumn(ColumnFilename).data(Qt::UserRole).toString().toUtf8(); strncpy(hdd[i].fn, fileName.data(), sizeof(hdd[i].fn) - 1); @@ -269,6 +279,53 @@ SettingsHarddisks::on_comboBoxSpeed_currentIndexChanged(int index) auto col = idx.siblingAtColumn(ColumnSpeed); model->setData(col, ui->comboBoxSpeed->currentData(Qt::UserRole), Qt::UserRole); model->setData(col, QObject::tr(hdd_preset_getname(ui->comboBoxSpeed->currentData(Qt::UserRole).toUInt()))); + + /* Reset audio profile to None when speed/model changes */ + auto audioCol = idx.siblingAtColumn(ColumnAudio); + model->setData(audioCol, 0, Qt::UserRole); + model->setData(audioCol, QObject::tr("None")); + } + + /* Repopulate audio profiles based on the selected speed preset's RPM */ + populateAudioProfiles(); +} + +void +SettingsHarddisks::populateAudioProfiles() +{ + ui->comboBoxAudio->clear(); + + /* Get RPM from currently selected speed preset */ + uint32_t target_rpm = hdd_preset_get_rpm(ui->comboBoxSpeed->currentData(Qt::UserRole).toUInt()); + + /* Populate audio profile combobox with matching RPM profiles */ + int profile_count = hdd_audio_get_profile_count(); + for (int i = 0; i < profile_count; i++) { + const char *name = hdd_audio_get_profile_name(i); + uint32_t profile_rpm = hdd_audio_get_profile_rpm(i); + + /* Include profile if it has no RPM set (0) or matches target RPM */ + if (name && (profile_rpm == 0 || profile_rpm == target_rpm)) { + ui->comboBoxAudio->addItem(name, i); + } + } +} + +void +SettingsHarddisks::on_comboBoxAudio_currentIndexChanged(int index) +{ + if (index < 0) + return; + + auto idx = ui->tableView->selectionModel()->currentIndex(); + if (idx.isValid()) { + auto *model = ui->tableView->model(); + auto col = idx.siblingAtColumn(ColumnAudio); + int prof = ui->comboBoxAudio->currentData(Qt::UserRole).toInt(); + model->setData(col, prof, Qt::UserRole); + + const char *audioName = hdd_audio_get_profile_name(prof); + model->setData(col, audioName ? QObject::tr(audioName) : QObject::tr("None")); } } @@ -279,13 +336,16 @@ SettingsHarddisks::onTableRowChanged(const QModelIndex ¤t) ui->labelBus->setHidden(hidden); ui->labelChannel->setHidden(hidden); ui->labelSpeed->setHidden(hidden); + ui->labelAudio->setHidden(hidden); ui->comboBoxBus->setHidden(hidden); ui->comboBoxChannel->setHidden(hidden); ui->comboBoxSpeed->setHidden(hidden); + ui->comboBoxAudio->setHidden(hidden); uint32_t bus = current.siblingAtColumn(ColumnBus).data(DataBus).toUInt(); uint32_t busChannel = current.siblingAtColumn(ColumnBus).data(DataBusChannel).toUInt(); uint32_t speed = current.siblingAtColumn(ColumnSpeed).data(Qt::UserRole).toUInt(); + uint32_t audio = current.siblingAtColumn(ColumnAudio).data(Qt::UserRole).toUInt(); auto *model = ui->comboBoxBus->model(); auto match = model->match(model->index(0, 0), Qt::UserRole, bus); @@ -302,6 +362,14 @@ SettingsHarddisks::onTableRowChanged(const QModelIndex ¤t) if (!match.isEmpty()) ui->comboBoxSpeed->setCurrentIndex(match.first().row()); + /* Populate audio profiles based on selected speed preset's RPM */ + populateAudioProfiles(); + + model = ui->comboBoxAudio->model(); + match = model->match(model->index(0, 0), Qt::UserRole, audio); + if (!match.isEmpty()) + ui->comboBoxAudio->setCurrentIndex(match.first().row()); + reloadBusChannels(); } diff --git a/src/qt/qt_settingsharddisks.hpp b/src/qt/qt_settingsharddisks.hpp index f892a79cdd6..f082c7de636 100644 --- a/src/qt/qt_settingsharddisks.hpp +++ b/src/qt/qt_settingsharddisks.hpp @@ -24,6 +24,7 @@ private slots: void on_comboBoxBus_currentIndexChanged(int index); void on_comboBoxChannel_currentIndexChanged(int index); void on_comboBoxSpeed_currentIndexChanged(int index); + void on_comboBoxAudio_currentIndexChanged(int index); void on_pushButtonNew_clicked(); void on_pushButtonExisting_clicked(); @@ -34,6 +35,7 @@ private slots: private: Ui::SettingsHarddisks *ui; void enableCurrentlySelectedChannel(); + void populateAudioProfiles(); bool buschangeinprogress = false; }; diff --git a/src/qt/qt_settingsharddisks.ui b/src/qt/qt_settingsharddisks.ui index e68de43d172..a6f134bdcb9 100644 --- a/src/qt/qt_settingsharddisks.ui +++ b/src/qt/qt_settingsharddisks.ui @@ -90,6 +90,20 @@ + + + + Audio: + + + + + + + 30 + + + @@ -98,14 +112,14 @@ - &New... + &New… - &Existing... + &Existing… diff --git a/src/qt/qt_settingsinput.ui b/src/qt/qt_settingsinput.ui index e4c0dc8fae1..679df5c541b 100644 --- a/src/qt/qt_settingsinput.ui +++ b/src/qt/qt_settingsinput.ui @@ -114,28 +114,28 @@ - Joystick 1... + Joystick 1… - Joystick 2... + Joystick 2… - Joystick 3... + Joystick 3… - Joystick 4... + Joystick 4… diff --git a/src/qt/qt_settingsnetwork.cpp b/src/qt/qt_settingsnetwork.cpp index fec607b9760..878944e6005 100644 --- a/src/qt/qt_settingsnetwork.cpp +++ b/src/qt/qt_settingsnetwork.cpp @@ -54,8 +54,8 @@ SettingsNetwork::enableElements(Ui::SettingsNetwork *ui) // auto *switch_group_hlayout = findChild(QString("HLayoutSwitch%1").arg(i + 1)); // auto *switch_group_hspacer = findChild(QString("horizontalSpacerSwitch%1").arg(i + 1)); auto *switch_group_value = findChild(QString("spinnerSwitch%1").arg(i + 1)); - switch_group_value->setMinimum(1); - switch_group_value->setMaximum(10); + switch_group_value->setMinimum(NET_SWITCH_GRP_MIN); + switch_group_value->setMaximum(NET_SWITCH_GRP_MAX); // Promiscuous option auto *promisc_label = findChild(QString("labelPromisc%1").arg(i + 1)); @@ -137,8 +137,7 @@ SettingsNetwork::enableElements(Ui::SettingsNetwork *ui) break; #endif -#ifdef USE_NETSWITCH - case NET_TYPE_NMSWITCH: + case NET_TYPE_NLSWITCH: // option_list_label->setText("Local Switch Options"); option_list_label->setVisible(true); option_list_line->setVisible(true); @@ -167,7 +166,6 @@ SettingsNetwork::enableElements(Ui::SettingsNetwork *ui) hostname_label->setVisible(true); hostname_value->setVisible(true); break; -#endif /* USE_NETSWITCH */ case NET_TYPE_SLIRP: default: @@ -215,11 +213,9 @@ SettingsNetwork::save() cbox = findChild(QString("comboBoxNet%1").arg(i + 1)); net_cards_conf[i].net_type = cbox->currentData().toInt(); cbox = findChild(QString("comboBoxIntf%1").arg(i + 1)); -#ifdef USE_NETSWITCH auto *hostname_value = findChild(QString("hostnameSwitch%1").arg(i + 1)); auto *promisc_value = findChild(QString("boxPromisc%1").arg(i + 1)); auto *switch_group_value = findChild(QString("spinnerSwitch%1").arg(i + 1)); -#endif /* USE_NETSWITCH */ memset(net_cards_conf[i].host_dev_name, '\0', sizeof(net_cards_conf[i].host_dev_name)); if (net_cards_conf[i].net_type == NET_TYPE_PCAP) strncpy(net_cards_conf[i].host_dev_name, network_devs[cbox->currentData().toInt()].device, sizeof(net_cards_conf[i].host_dev_name) - 1); @@ -231,16 +227,14 @@ SettingsNetwork::save() else if (net_cards_conf[i].net_type == NET_TYPE_TAP) strncpy(net_cards_conf[i].host_dev_name, bridge_line->text().toUtf8().constData(), sizeof(net_cards_conf[i].host_dev_name)); #endif -#ifdef USE_NETSWITCH else if (net_cards_conf[i].net_type == NET_TYPE_NRSWITCH) { memset(net_cards_conf[i].nrs_hostname, '\0', sizeof(net_cards_conf[i].nrs_hostname)); strncpy(net_cards_conf[i].nrs_hostname, hostname_value->text().toUtf8().constData(), sizeof(net_cards_conf[i].nrs_hostname) - 1); - net_cards_conf[i].switch_group = switch_group_value->value() - 1; - } else if (net_cards_conf[i].net_type == NET_TYPE_NMSWITCH) { + net_cards_conf[i].switch_group = switch_group_value->value(); + } else if (net_cards_conf[i].net_type == NET_TYPE_NLSWITCH) { net_cards_conf[i].promisc_mode = promisc_value->isChecked(); - net_cards_conf[i].switch_group = switch_group_value->value() - 1; + net_cards_conf[i].switch_group = switch_group_value->value(); } -#endif /* USE_NETSWITCH */ } } @@ -313,12 +307,10 @@ SettingsNetwork::onCurrentMachineChanged(int machineId) Models::AddEntry(model, "TAP", NET_TYPE_TAP); #endif -#ifdef USE_NETSWITCH - Models::AddEntry(model, "Local Switch", NET_TYPE_NMSWITCH); -# ifdef ENABLE_NET_NRSWITCH + Models::AddEntry(model, "Local Switch", NET_TYPE_NLSWITCH); +#ifdef ENABLE_NET_NRSWITCH Models::AddEntry(model, "Remote Switch", NET_TYPE_NRSWITCH); -# endif /* ENABLE_NET_NRSWITCH */ -#endif /* USE_NETSWITCH */ +#endif /* ENABLE_NET_NRSWITCH */ model->removeRows(0, removeRows); cbox->setCurrentIndex(cbox->findData(net_cards_conf[i].net_type)); @@ -354,18 +346,16 @@ SettingsNetwork::onCurrentMachineChanged(int machineId) auto editline = findChild(QString("bridgeTAPNIC%1").arg(i + 1)); editline->setText(currentTapDevice); #endif -#ifdef USE_NETSWITCH - } else if (net_cards_conf[i].net_type == NET_TYPE_NMSWITCH) { + } else if (net_cards_conf[i].net_type == NET_TYPE_NLSWITCH) { auto *promisc_value = findChild(QString("boxPromisc%1").arg(i + 1)); promisc_value->setCheckState(net_cards_conf[i].promisc_mode == 1 ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); auto *switch_group_value = findChild(QString("spinnerSwitch%1").arg(i + 1)); - switch_group_value->setValue(net_cards_conf[i].switch_group + 1); + switch_group_value->setValue(net_cards_conf[i].switch_group); } else if (net_cards_conf[i].net_type == NET_TYPE_NRSWITCH) { auto *hostname_value = findChild(QString("hostnameSwitch%1").arg(i + 1)); hostname_value->setText(net_cards_conf[i].nrs_hostname); auto *switch_group_value = findChild(QString("spinnerSwitch%1").arg(i + 1)); - switch_group_value->setValue(net_cards_conf[i].switch_group + 1); -#endif /* USE_NETSWITCH */ + switch_group_value->setValue(net_cards_conf[i].switch_group); } } } diff --git a/src/qt/qt_settingsotherremovable.cpp b/src/qt/qt_settingsotherremovable.cpp index 7b3bb89f634..567eaa3e2e0 100644 --- a/src/qt/qt_settingsotherremovable.cpp +++ b/src/qt/qt_settingsotherremovable.cpp @@ -18,6 +18,7 @@ #include "ui_qt_settingsotherremovable.h" extern "C" { +#include <86box/86box.h> #include <86box/timer.h> #include <86box/scsi_device.h> #include <86box/mo.h> diff --git a/src/qt/qt_settingssound.cpp b/src/qt/qt_settingssound.cpp index 6307451a5b5..cb5368def8a 100644 --- a/src/qt/qt_settingssound.cpp +++ b/src/qt/qt_settingssound.cpp @@ -89,8 +89,8 @@ SettingsSound::onCurrentMachineChanged(const int machineId) c = 0; while (true) { - const QString name = DeviceConfig::DeviceName(sound_card_getdevice(c), - sound_card_get_internal_name(c), 1); + QString name = DeviceConfig::DeviceName(sound_card_getdevice(c), + sound_card_get_internal_name(c), 1); if (name.isEmpty()) break; @@ -99,6 +99,9 @@ SettingsSound::onCurrentMachineChanged(const int machineId) if (device_is_valid(sound_card_getdevice(c), machineId)) { for (uint8_t i = 0; i < SOUND_CARD_MAX; ++i) { if ((c != 1) || ((i == 0) && m_has_snd)) { + if (i == 0 && c == 1 && m_has_snd && machine_get_snd_device(machineId)) { + name += QString(" (%1)").arg(DeviceConfig::DeviceName(machine_get_snd_device(machineId), machine_get_snd_device(machineId)->internal_name, 0)); + } int row = Models::AddEntry(models[i], name, c); if (c == sound_card_current[i]) diff --git a/src/qt/qt_settingsstoragecontrollers.ui b/src/qt/qt_settingsstoragecontrollers.ui index 50ebbe7ef82..adb80064a1c 100644 --- a/src/qt/qt_settingsstoragecontrollers.ui +++ b/src/qt/qt_settingsstoragecontrollers.ui @@ -31,7 +31,7 @@ - FD Controller: + Floppy disk controller: @@ -58,7 +58,7 @@ - CD-ROM Controller: + CD-ROM controller: @@ -87,7 +87,7 @@ - Hard disk + Hard disk controllers @@ -204,7 +204,7 @@ - SCSI + SCSI controllers diff --git a/src/qt/qt_softwarerenderer.cpp b/src/qt/qt_softwarerenderer.cpp index 0a4492a3e50..d9e217ed327 100644 --- a/src/qt/qt_softwarerenderer.cpp +++ b/src/qt/qt_softwarerenderer.cpp @@ -18,21 +18,19 @@ */ #include "qt_softwarerenderer.hpp" #include +#include #include #include extern "C" { #include <86box/86box.h> +#include <86box/path.h> +#include <86box/plat.h> #include <86box/video.h> } SoftwareRenderer::SoftwareRenderer(QWidget *parent) -#ifdef __HAIKU__ : QWidget(parent) -#else - : QWindow(parent->windowHandle()) - , m_backingStore(new QBackingStore(this)) -#endif { RendererCommon::parentWidget = parent; @@ -42,25 +40,23 @@ SoftwareRenderer::SoftwareRenderer(QWidget *parent) buf_usage = std::vector(2); buf_usage[0].clear(); buf_usage[1].clear(); -#ifdef __HAIKU__ this->setMouseTracking(true); -#endif } -#ifdef __HAIKU__ void SoftwareRenderer::paintEvent(QPaintEvent *event) { (void) event; onPaint(this); } -#endif void SoftwareRenderer::render() { +#ifdef __HAIKU__ if (!isExposed()) return; +#endif QRect rect(0, 0, width(), height()); m_backingStore->beginPaint(rect); @@ -78,6 +74,8 @@ SoftwareRenderer::exposeEvent(QExposeEvent *event) render(); } +extern void take_screenshot_clipboard_monitor(int sx, int sy, int sw, int sh, int i); + void SoftwareRenderer::onBlit(int buf_idx, int x, int y, int w, int h) { @@ -94,24 +92,52 @@ SoftwareRenderer::onBlit(int buf_idx, int x, int y, int w, int h) if (source != origSource) onResize(this->width(), this->height()); -#ifdef __HAIKU__ + update(); -#else - render(); -#endif + + if (monitors[r_monitor_index].mon_screenshots) { + char path[1024]; + char fn[256]; + + memset(fn, 0, sizeof(fn)); + memset(path, 0, sizeof(path)); + + path_append_filename(path, usr_path, SCREENSHOT_PATH); + + if (!plat_dir_check(path)) + plat_dir_create(path); + + path_slash(path); + strcat(path, "Monitor_"); + snprintf(&path[strlen(path)], 42, "%d_", r_monitor_index + 1); + + plat_tempfile(fn, NULL, (char *) ".png"); + strcat(path, fn); + + QPixmap pixmap(RendererCommon::parentWidget->size()); + RendererCommon::parentWidget->render(&pixmap); + QImage image = pixmap.toImage(); + image.save(path, "png"); + monitors[r_monitor_index].mon_screenshots--; + } + if (monitors[r_monitor_index].mon_screenshots_clipboard) { + QPixmap pixmap(RendererCommon::parentWidget->size()); + RendererCommon::parentWidget->render(&pixmap); + QImage image = pixmap.toImage(); + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setImage(image, QClipboard::Clipboard); + monitors[r_monitor_index].mon_screenshots_clipboard--; + } + if (monitors[r_monitor_index].mon_screenshots_raw_clipboard) { + take_screenshot_clipboard_monitor(x, y, w, h, r_monitor_index); + } } void SoftwareRenderer::resizeEvent(QResizeEvent *event) { onResize(width(), height()); -#ifdef __HAIKU__ QWidget::resizeEvent(event); -#else - QWindow::resizeEvent(event); - m_backingStore->resize(event->size()); - render(); -#endif } bool @@ -119,11 +145,7 @@ SoftwareRenderer::event(QEvent *event) { bool res = false; if (!eventDelegate(event, res)) -#ifdef __HAIKU__ return QWidget::event(event); -#else - return QWindow::event(event); -#endif return res; } @@ -142,9 +164,7 @@ SoftwareRenderer::onPaint(QPaintDevice *device) #endif painter.setCompositionMode(QPainter::CompositionMode_Plus); painter.drawImage(destination, *images[cur_image], source); -#ifndef __HAIKU__ painter.end(); -#endif } std::vector> diff --git a/src/qt/qt_softwarerenderer.hpp b/src/qt/qt_softwarerenderer.hpp index e80410956b1..a2b11c01219 100644 --- a/src/qt/qt_softwarerenderer.hpp +++ b/src/qt/qt_softwarerenderer.hpp @@ -11,21 +11,19 @@ #include "qt_renderercommon.hpp" class SoftwareRenderer : -#ifdef __HAIKU__ public QWidget, -#else - public QWindow, -#endif public RendererCommon { Q_OBJECT public: explicit SoftwareRenderer(QWidget *parent = nullptr); -#ifdef __HAIKU__ void paintEvent(QPaintEvent *event) override; -#endif +#ifdef __HAIKU__ void exposeEvent(QExposeEvent *event) override; +#else + void exposeEvent(QExposeEvent *event); +#endif std::vector> getBuffers() override; diff --git a/src/qt/qt_soundgain.ui b/src/qt/qt_soundgain.ui index 8d3f2c3f6b6..06ea38c1059 100644 --- a/src/qt/qt_soundgain.ui +++ b/src/qt/qt_soundgain.ui @@ -31,7 +31,20 @@ Sound Gain - + + + + + Qt::Horizontal + + + + 40 + 20 + + + + @@ -48,7 +61,107 @@ - + + + + +18 dB + + + Qt::AlignRight + + + + + + + +16 dB + + + Qt::AlignRight + + + + + + + +14 dB + + + Qt::AlignRight + + + + + + + +12 dB + + + Qt::AlignRight + + + + + + + +10 dB + + + Qt::AlignRight + + + + + + + +8 dB + + + Qt::AlignRight + + + + + + + +6 dB + + + Qt::AlignRight + + + + + + + +4 dB + + + Qt::AlignRight + + + + + + + +2 dB + + + Qt::AlignRight + + + + + + + 0 dB + + + Qt::AlignRight + + + + 18 @@ -70,7 +183,7 @@ - + diff --git a/src/qt/qt_translations.qrc.in b/src/qt/qt_translations.qrc.in index ef79933722b..016160b52b3 100644 --- a/src/qt/qt_translations.qrc.in +++ b/src/qt/qt_translations.qrc.in @@ -1,7 +1,9 @@ + 86box_ca-ES.qm 86box_cs-CZ.qm 86box_de-DE.qm + 86box_el-GR.qm 86box_en-US.qm 86box_en-GB.qm 86box_es-ES.qm diff --git a/src/qt/qt_updatecheckdialog.ui b/src/qt/qt_updatecheckdialog.ui index 3fd2942fdf0..d4cba42aa13 100644 --- a/src/qt/qt_updatecheckdialog.ui +++ b/src/qt/qt_updatecheckdialog.ui @@ -41,7 +41,7 @@ - Checking for updates... + Checking for updates… Qt::AlignCenter diff --git a/src/qt/qt_vmmanager_config.cpp b/src/qt/qt_vmmanager_config.cpp index 70fcdcc6c56..b49446dbb95 100644 --- a/src/qt/qt_vmmanager_config.cpp +++ b/src/qt/qt_vmmanager_config.cpp @@ -18,8 +18,18 @@ extern "C" { #include <86box/plat.h> +#include <86box/version.h> } +QVariantHash VMManagerConfig::generalDefaults = { + { "hide_tool_bar", 0 }, + { "regex_search", 0 }, +#if EMU_BUILD_NUM != 0 + { "update_check", 1 }, +#endif + { "window_remember", 0 } +}; + VMManagerConfig::VMManagerConfig(const ConfigType type, const QString §ion) { char BUF[256]; @@ -36,6 +46,8 @@ VMManagerConfig::VMManagerConfig(const ConfigType type, const QString §ion) settings->setFallbacksEnabled(false); if (type == ConfigType::System && !section.isEmpty()) { settings->beginGroup(section); + } else { + settings->beginGroup(""); } } @@ -47,7 +59,10 @@ VMManagerConfig::~VMManagerConfig() QString VMManagerConfig::getStringValue(const QString &key) const { - const auto value = settings->value(key); + auto defaultValue = QVariant(); + if ((config_type == ConfigType::General) && (generalDefaults.contains(key))) + defaultValue = generalDefaults[key]; + const auto value = settings->value(key, defaultValue); // An invalid QVariant with toString will give a default QString value which is blank. // Therefore any variables that do not exist will return blank strings return value.toString(); diff --git a/src/qt/qt_vmmanager_config.hpp b/src/qt/qt_vmmanager_config.hpp index 814b3c70f75..e9c804a7e3f 100644 --- a/src/qt/qt_vmmanager_config.hpp +++ b/src/qt/qt_vmmanager_config.hpp @@ -35,6 +35,8 @@ class VMManagerConfig : QObject { void sync() const; + static QVariantHash generalDefaults; + QSettings *settings; ConfigType config_type; QString system_name; diff --git a/src/qt/qt_vmmanager_details.cpp b/src/qt/qt_vmmanager_details.cpp index e0cabc53c67..40d0fb18569 100644 --- a/src/qt/qt_vmmanager_details.cpp +++ b/src/qt/qt_vmmanager_details.cpp @@ -16,6 +16,11 @@ #include #include +extern "C" { +#include <86box/86box.h> +} + +#include "qt_progsettings.hpp" #include "qt_util.hpp" #include "qt_vmmanager_details.hpp" #include "ui_qt_vmmanager_details.h" @@ -88,21 +93,12 @@ VMManagerDetails::VMManagerDetails(QWidget *parent) // Set the icons for the screenshot navigation buttons ui->screenshotNext->setIcon(QApplication::style()->standardIcon(QStyle::SP_ArrowRight)); ui->screenshotPrevious->setIcon(QApplication::style()->standardIcon(QStyle::SP_ArrowLeft)); - ui->screenshotNextTB->setIcon(QApplication::style()->standardIcon(QStyle::SP_ArrowRight)); - ui->screenshotPreviousTB->setIcon(QApplication::style()->standardIcon(QStyle::SP_ArrowLeft)); // Disabled by default ui->screenshotNext->setEnabled(false); ui->screenshotPrevious->setEnabled(false); - ui->screenshotNextTB->setEnabled(false); - ui->screenshotPreviousTB->setEnabled(false); // Connect their signals - connect(ui->screenshotNext, &QPushButton::clicked, this, &VMManagerDetails::nextScreenshot); - connect(ui->screenshotNextTB, &QToolButton::clicked, this, &VMManagerDetails::nextScreenshot); - connect(ui->screenshotPreviousTB, &QToolButton::clicked, this, &VMManagerDetails::previousScreenshot); - connect(ui->screenshotPrevious, &QPushButton::clicked, this, &VMManagerDetails::previousScreenshot); - // These push buttons can be taken out if the tool buttons stay - ui->screenshotNext->setVisible(false); - ui->screenshotPrevious->setVisible(false); + connect(ui->screenshotNext, &QToolButton::clicked, this, &VMManagerDetails::nextScreenshot); + connect(ui->screenshotPrevious, &QToolButton::clicked, this, &VMManagerDetails::previousScreenshot); QString toolButtonStyleSheet; // Simple method to try and determine if light mode is enabled #ifdef Q_OS_WINDOWS @@ -117,6 +113,13 @@ VMManagerDetails::VMManagerDetails(QWidget *parent) } ui->ssNavTBHolder->setStyleSheet(toolButtonStyleSheet); + // Margins are a little different on macos +#ifdef Q_OS_MACOS + ui->systemLabel->setMargin(15); +#else + ui->systemLabel->setMargin(10); +#endif + pauseIcon = QIcon(":/menuicons/qt/icons/pause.ico"); runIcon = QIcon(":/menuicons/qt/icons/run.ico"); @@ -138,17 +141,17 @@ VMManagerDetails::VMManagerDetails(QWidget *parent) configureButton = new QToolButton(); configureButton->setIcon(QIcon(":/menuicons/qt/icons/settings.ico")); configureButton->setEnabled(false); - configureButton->setToolTip(tr("Settings...")); + configureButton->setToolTip(tr("Settings…")); cadButton = new QToolButton(); cadButton->setIcon(QIcon(":menuicons/qt/icons/send_cad.ico")); cadButton->setEnabled(false); cadButton->setToolTip(tr("Ctrl+Alt+Del")); - ui->toolButtonHolder->layout()->addWidget(configureButton); + ui->toolButtonHolder->layout()->addWidget(startPauseButton); ui->toolButtonHolder->layout()->addWidget(resetButton); ui->toolButtonHolder->layout()->addWidget(stopButton); - ui->toolButtonHolder->layout()->addWidget(startPauseButton); ui->toolButtonHolder->layout()->addWidget(cadButton); + ui->toolButtonHolder->layout()->addWidget(configureButton); ui->notesTextEdit->setEnabled(false); @@ -161,6 +164,8 @@ VMManagerDetails::VMManagerDetails(QWidget *parent) connect(this, &VMManagerDetails::styleUpdated, inputSection, &VMManagerDetailSection::updateStyle); connect(this, &VMManagerDetails::styleUpdated, portsSection, &VMManagerDetailSection::updateStyle); connect(this, &VMManagerDetails::styleUpdated, otherSection, &VMManagerDetailSection::updateStyle); + + QApplication::setFont(QFont(ProgSettings::getFontName(lang_id), 9)); #endif sysconfig = new VMManagerSystem(); @@ -171,6 +176,59 @@ VMManagerDetails::~VMManagerDetails() delete ui; } +void +VMManagerDetails::reset() +{ + systemSection->clear(); + videoSection->clear(); + storageSection->clear(); + audioSection->clear(); + networkSection->clear(); + inputSection->clear(); + portsSection->clear(); + otherSection->clear(); + systemSection->setSections(); + videoSection->setSections(); + storageSection->setSections(); + audioSection->setSections(); + networkSection->setSections(); + inputSection->setSections(); + portsSection->setSections(); + otherSection->setSections(); + + ui->screenshotNext->setEnabled(false); + ui->screenshotPrevious->setEnabled(false); + ui->screenshot->setPixmap(QString()); + ui->screenshot->setFixedSize(240, 160); + ui->screenshot->setFrameStyle(QFrame::Box | QFrame::Sunken); + ui->screenshot->setText(tr("No screenshot")); + ui->screenshot->setEnabled(false); + ui->screenshot->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); +#ifdef Q_OS_WINDOWS + if (!util::isWindowsLightTheme()) { + ui->screenshot->setStyleSheet(SCREENSHOTBORDER_STYLESHEET_DARK); + } else { + ui->screenshot->setStyleSheet(""); + } +#endif + + startPauseButton->setEnabled(false); + resetButton->setEnabled(false); + stopButton->setEnabled(false); + configureButton->setEnabled(false); + cadButton->setEnabled(false); + + ui->systemLabel->setText(tr("No Machines Found!")); + ui->systemLabel->setStyleSheet(""); + ui->statusLabel->setText(""); + ui->scrollArea->setStyleSheet(""); + + ui->notesTextEdit->setPlainText(""); + ui->notesTextEdit->setEnabled(false); + + sysconfig = new VMManagerSystem(); +} + void VMManagerDetails::updateData(VMManagerSystem *passed_sysconfig) { @@ -184,12 +242,6 @@ VMManagerDetails::updateData(VMManagerSystem *passed_sysconfig) ui->scrollArea->setStyleSheet(SCROLLAREA_STYLESHEET_LIGHT); ui->systemLabel->setStyleSheet(SYSTEMLABEL_STYLESHEET_LIGHT); } - // Margins are a little different on macos -#ifdef Q_OS_MACOS - ui->systemLabel->setMargin(15); -#else - ui->systemLabel->setMargin(10); -#endif // disconnect old signals before assigning the passed systemconfig object disconnect(startPauseButton, &QToolButton::clicked, sysconfig, &VMManagerSystem::startButtonPressed); @@ -199,6 +251,8 @@ VMManagerDetails::updateData(VMManagerSystem *passed_sysconfig) disconnect(configureButton, &QToolButton::clicked, sysconfig, &VMManagerSystem::launchSettings); disconnect(cadButton, &QToolButton::clicked, sysconfig, &VMManagerSystem::cadButtonPressed); + disconnect(sysconfig, &VMManagerSystem::configurationChanged, this, &VMManagerDetails::onConfigUpdated); + sysconfig = passed_sysconfig; connect(resetButton, &QToolButton::clicked, sysconfig, &VMManagerSystem::restartButtonPressed); connect(stopButton, &QToolButton::clicked, sysconfig, &VMManagerSystem::shutdownForceButtonPressed); @@ -234,9 +288,18 @@ VMManagerDetails::updateData(VMManagerSystem *passed_sysconfig) disconnect(sysconfig, &VMManagerSystem::clientProcessStatusChanged, this, &VMManagerDetails::updateProcessStatus); connect(sysconfig, &VMManagerSystem::clientProcessStatusChanged, this, &VMManagerDetails::updateProcessStatus); + connect(sysconfig, &VMManagerSystem::configurationChanged, this, &VMManagerDetails::onConfigUpdated); + updateProcessStatus(); } +void +VMManagerDetails::onConfigUpdated(VMManagerSystem *passed_sysconfig) +{ + updateConfig(passed_sysconfig); + updateScreenshots(passed_sysconfig); +} + void VMManagerDetails::updateConfig(VMManagerSystem *passed_sysconfig) { @@ -310,8 +373,6 @@ VMManagerDetails::updateScreenshots(VMManagerSystem *passed_sysconfig) // Disable screenshot navigation buttons by default ui->screenshotNext->setEnabled(false); ui->screenshotPrevious->setEnabled(false); - ui->screenshotNextTB->setEnabled(false); - ui->screenshotPreviousTB->setEnabled(false); // Different actions are taken depending on the existence and number of screenshots screenshots = passed_sysconfig->getScreenshots(); @@ -321,8 +382,6 @@ VMManagerDetails::updateScreenshots(VMManagerSystem *passed_sysconfig) if (screenshots.size() > 1) { ui->screenshotNext->setEnabled(true); ui->screenshotPrevious->setEnabled(true); - ui->screenshotNextTB->setEnabled(true); - ui->screenshotPreviousTB->setEnabled(true); } #ifdef Q_OS_WINDOWS ui->screenshot->setStyleSheet(""); @@ -335,8 +394,6 @@ VMManagerDetails::updateScreenshots(VMManagerSystem *passed_sysconfig) } else { ui->screenshotNext->setEnabled(false); ui->screenshotPrevious->setEnabled(false); - ui->screenshotNextTB->setEnabled(false); - ui->screenshotPreviousTB->setEnabled(false); ui->screenshot->setPixmap(QString()); ui->screenshot->setFixedSize(240, 160); ui->screenshot->setFrameStyle(QFrame::Box | QFrame::Sunken); diff --git a/src/qt/qt_vmmanager_details.hpp b/src/qt/qt_vmmanager_details.hpp index ec71d4cd8e8..489f74a2596 100644 --- a/src/qt/qt_vmmanager_details.hpp +++ b/src/qt/qt_vmmanager_details.hpp @@ -35,6 +35,8 @@ class VMManagerDetails : public QWidget { ~VMManagerDetails() override; + void reset(); + void updateData(VMManagerSystem *passed_sysconfig); void updateProcessStatus(); @@ -87,6 +89,7 @@ private slots: void saveNotes() const; void nextScreenshot(); void previousScreenshot(); + void onConfigUpdated(VMManagerSystem *passed_sysconfig); protected: bool eventFilter(QObject *watched, QEvent *event) override; diff --git a/src/qt/qt_vmmanager_details.ui b/src/qt/qt_vmmanager_details.ui index 9b4fbbe8bb8..0722dd3f5b9 100644 --- a/src/qt/qt_vmmanager_details.ui +++ b/src/qt/qt_vmmanager_details.ui @@ -146,22 +146,6 @@ - - - - - 0 - 0 - - - - - - - false - - - @@ -178,16 +162,16 @@ 0 - + - ... + - + - ... + true @@ -197,19 +181,6 @@ - - - - - 0 - 0 - - - - - - - diff --git a/src/qt/qt_vmmanager_listviewdelegate.cpp b/src/qt/qt_vmmanager_listviewdelegate.cpp index 88d123ce90a..2935cdbe4ec 100644 --- a/src/qt/qt_vmmanager_listviewdelegate.cpp +++ b/src/qt/qt_vmmanager_listviewdelegate.cpp @@ -246,7 +246,7 @@ VMManagerListViewDelegateStyle::statusBox(const QStyleOptionViewItem &option, qreal VMManagerListViewDelegateStyle::statusFontPointSize(const QFont &f) const { - return 0.75 * f.pointSize(); + return 0.9 * f.pointSize(); // return 1*f.pointSize(); } diff --git a/src/qt/qt_vmmanager_main.cpp b/src/qt/qt_vmmanager_main.cpp index 54e0c619fae..317bd0f2beb 100644 --- a/src/qt/qt_vmmanager_main.cpp +++ b/src/qt/qt_vmmanager_main.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -97,7 +98,7 @@ VMManagerMain::VMManagerMain(QWidget *parent) connect(ui->listView, &QListView::customContextMenuRequested, [this, parent](const QPoint &pos) { const auto indexAt = ui->listView->indexAt(pos); if (indexAt.isValid()) { - QMenu contextMenu(tr("Context Menu"), ui->listView); + QMenu contextMenu("", ui->listView); QAction startAction(tr("&Start")); contextMenu.addAction(&startAction); @@ -140,13 +141,13 @@ VMManagerMain::VMManagerMain(QWidget *parent) contextMenu.addSeparator(); - QAction settingsAction(tr("&Settings...")); + QAction settingsAction(tr("&Settings…")); contextMenu.addAction(&settingsAction); connect(&settingsAction, &QAction::triggered, [this] { selected_sysconfig->launchSettings(); }); - QAction nameChangeAction(tr("Change &display name...")); + QAction nameChangeAction(tr("Change &display name…")); contextMenu.addAction(&nameChangeAction); // Use a lambda to call a function so indexAt can be passed connect(&nameChangeAction, &QAction::triggered, ui->listView, [this, indexAt] { @@ -154,7 +155,7 @@ VMManagerMain::VMManagerMain(QWidget *parent) }); nameChangeAction.setEnabled(!selected_sysconfig->window_obscured); - QAction setSystemIcon(tr("Set &icon...")); + QAction setSystemIcon(tr("Set &icon…")); contextMenu.addAction(&setSystemIcon); connect(&setSystemIcon, &QAction::triggered, [this] { IconSelectionDialog dialog(":/systemicons/"); @@ -168,7 +169,7 @@ VMManagerMain::VMManagerMain(QWidget *parent) contextMenu.addSeparator(); - QAction cloneMachine(tr("C&lone...")); + QAction cloneMachine(tr("C&lone…")); contextMenu.addAction(&cloneMachine); connect(&cloneMachine, &QAction::triggered, [this] { QDialog dialog = QDialog(this); @@ -287,6 +288,7 @@ VMManagerMain::VMManagerMain(QWidget *parent) // Get the index of the newly-created system and select it const QModelIndex mapped_index = proxy_model->mapFromSource(created_object); ui->listView->setCurrentIndex(mapped_index); + modelDataChange(); } else { QDir(dstPath).removeRecursively(); QMessageBox::critical(this, tr("Clone"), tr("Failed to clone VM."), QMessageBox::Ok); @@ -331,7 +333,7 @@ VMManagerMain::VMManagerMain(QWidget *parent) contextMenu.addSeparator(); - QAction openSystemFolderAction(tr("&Open folder...")); + QAction openSystemFolderAction(tr("&Open folder…")); contextMenu.addAction(&openSystemFolderAction); connect(&openSystemFolderAction, &QAction::triggered, [indexAt] { if (const auto configDir = indexAt.data(VMManagerModel::Roles::ConfigDir).toString(); !configDir.isEmpty()) { @@ -343,7 +345,7 @@ VMManagerMain::VMManagerMain(QWidget *parent) } }); - QAction openPrinterFolderAction(tr("Open p&rinter tray...")); + QAction openPrinterFolderAction(tr("Open p&rinter tray…")); contextMenu.addAction(&openPrinterFolderAction); connect(&openPrinterFolderAction, &QAction::triggered, [indexAt] { if (const auto printerDir = indexAt.data(VMManagerModel::Roles::ConfigDir).toString() + QString("/printer/"); !printerDir.isEmpty()) { @@ -355,7 +357,7 @@ VMManagerMain::VMManagerMain(QWidget *parent) } }); - QAction openScreenshotsFolderAction(tr("Open screenshots &folder...")); + QAction openScreenshotsFolderAction(tr("Open screenshots &folder…")); contextMenu.addAction(&openScreenshotsFolderAction); connect(&openScreenshotsFolderAction, &QAction::triggered, [indexAt] { if (const auto screenshotsDir = indexAt.data(VMManagerModel::Roles::ConfigDir).toString() + QString("/screenshots/"); !screenshotsDir.isEmpty()) { @@ -377,9 +379,9 @@ VMManagerMain::VMManagerMain(QWidget *parent) contextMenu.exec(ui->listView->viewport()->mapToGlobal(pos)); } else { - QMenu contextMenu(tr("Context Menu"), ui->listView); + QMenu contextMenu("", ui->listView); - QAction newMachineAction(tr("&New machine...")); + QAction newMachineAction(tr("&New machine…")); contextMenu.addAction(&newMachineAction); connect(&newMachineAction, &QAction::triggered, this, &VMManagerMain::newMachineWizard); @@ -404,8 +406,13 @@ VMManagerMain::VMManagerMain(QWidget *parent) ui->listView->setCurrentIndex(first_index); } + // Connect double-click to start VM connect(ui->listView, &QListView::doubleClicked, this, &VMManagerMain::startButtonPressed); + // Connect Enter key to start VM + auto enterShortcut = new QShortcut(QKeySequence(Qt::Key_Return), ui->listView); + connect(enterShortcut, &QShortcut::activated, this, &VMManagerMain::startButtonPressed); + // Load and apply settings loadSettings(); ui->splitter->setSizes({ ui->detailsArea->width(), (ui->listView->minimumWidth() * 2) }); @@ -423,9 +430,11 @@ VMManagerMain::VMManagerMain(QWidget *parent) completer->setModel(completerModel); ui->searchBar->setCompleter(completer); - // Set initial status bar after the event loop starts QTimer::singleShot(0, this, [this] { + // Set initial status bar after the event loop starts emit updateStatusRight(machineCountString()); + // Tell the mainwindow to enable the toolbar buttons if needed + emit selectionOrStateChanged((this->proxy_model->rowCount(QModelIndex()) > 0) ? selected_sysconfig : nullptr); }); #if EMU_BUILD_NUM != 0 @@ -443,6 +452,56 @@ VMManagerMain::~VMManagerMain() delete vm_model; } +void +VMManagerMain::reload() +{ + // Disconnect and save the old selection mdoel to be deleted later + QItemSelectionModel *old_selection_model = ui->listView->selectionModel(); + disconnect(old_selection_model, &QItemSelectionModel::currentChanged, this, &VMManagerMain::currentSelectionChanged); + // Disconnect and delete the model and proxy model + disconnect(vm_model, &VMManagerModel::systemDataChanged, this, &VMManagerMain::modelDataChange); + disconnect(vm_model, &VMManagerModel::globalConfigurationChanged, this, nullptr); + delete proxy_model; + delete vm_model; + + // Reset the details view and toolbar to initial state + selected_sysconfig = new VMManagerSystem(); + vm_details->reset(); + emit selectionOrStateChanged(nullptr); + + // Create the new model and proxy model + vm_model = new VMManagerModel; + proxy_model = new StringListProxyModel(this); + proxy_model->setSourceModel(vm_model); + ui->listView->setModel(proxy_model); + // Delete the old selection model + delete old_selection_model; + + // Set up the new models + proxy_model->setSortCaseSensitivity(Qt::CaseInsensitive); + ui->listView->model()->sort(0, Qt::AscendingOrder); + connect(vm_model, &VMManagerModel::systemDataChanged, this, &VMManagerMain::modelDataChange); + connect(vm_model, &VMManagerModel::globalConfigurationChanged, this, []() { + vmm_main_window->updateSettings(); + }); + const QItemSelectionModel *selection_model = ui->listView->selectionModel(); + connect(selection_model, &QItemSelectionModel::currentChanged, this, &VMManagerMain::currentSelectionChanged); + + // Update the search completer + auto *completerModel = new QStringListModel(getSearchCompletionList(), ui->searchBar->completer()); + ui->searchBar->completer()->setModel(completerModel); + + // If machines are found, set the selection to the first one + if (proxy_model->rowCount(QModelIndex()) > 0) { + const QModelIndex first_index = proxy_model->index(0, 0); + ui->listView->setCurrentIndex(first_index); + emit selectionOrStateChanged(selected_sysconfig); + } + + // Notify the status bar + emit updateStatusRight(machineCountString()); +} + void VMManagerMain::updateGlobalSettings() { @@ -456,22 +515,21 @@ VMManagerMain::currentSelectionChanged(const QModelIndex ¤t, if (!current.isValid()) return; - /* hack to prevent strange segfaults when adding a machine after - removing all machines previously */ - if (selected_sysconfig->config_signal_connected == true) { - disconnect(selected_sysconfig, &VMManagerSystem::configurationChanged, this, &VMManagerMain::onConfigUpdated); - selected_sysconfig->config_signal_connected = false; - } + disconnect(selected_sysconfig->process, &QProcess::stateChanged, this, &VMManagerMain::vmStateChange); + disconnect(selected_sysconfig, &VMManagerSystem::windowStatusChanged, this, &VMManagerMain::vmStateChange); + disconnect(selected_sysconfig, &VMManagerSystem::clientProcessStatusChanged, this, &VMManagerMain::vmStateChange); + const auto mapped_index = proxy_model->mapToSource(current); selected_sysconfig = vm_model->getConfigObjectForIndex(mapped_index); vm_details->updateData(selected_sysconfig); - if (selected_sysconfig->config_signal_connected == false) { - connect(selected_sysconfig, &VMManagerSystem::configurationChanged, this, &VMManagerMain::onConfigUpdated); - selected_sysconfig->config_signal_connected = true; - } // Emit that the selection changed, include with the process state - emit selectionChanged(current, selected_sysconfig->process->state()); + emit selectionOrStateChanged(selected_sysconfig); + + connect(selected_sysconfig->process, &QProcess::stateChanged, this, &VMManagerMain::vmStateChange); + connect(selected_sysconfig, &VMManagerSystem::windowStatusChanged, this, &VMManagerMain::vmStateChange); + connect(selected_sysconfig, &VMManagerSystem::clientProcessStatusChanged, this, &VMManagerMain::vmStateChange); + } void @@ -528,17 +586,13 @@ VMManagerMain::shutdownForceButtonPressed() const selected_sysconfig->shutdownForceButtonPressed(); } -// This function doesn't appear to be needed any longer void -VMManagerMain::refresh() +VMManagerMain::cadButtonPressed() const { - const auto current_index = ui->listView->currentIndex(); - emit selectionChanged(current_index, selected_sysconfig->process->state()); + if (!currentSelectionIsValid()) + return; - // if(!selected_sysconfig->config_file.path().isEmpty()) { - if (!selected_sysconfig->isValid()) { - // what was happening here? - } + selected_sysconfig->cadButtonPressed(); } void @@ -593,12 +647,6 @@ VMManagerMain::currentSelectionIsValid() const return ui->listView->currentIndex().isValid() && selected_sysconfig->isValid(); } -void -VMManagerMain::onConfigUpdated(const QString &uuid) -{ - if (selected_sysconfig->uuid == uuid) - vm_details->updateData(selected_sysconfig); -} // Used from MainWindow during app exit to obtain and persist the current selection QString VMManagerMain::getCurrentSelection() const @@ -717,6 +765,7 @@ VMManagerMain::addNewSystem(const QString &name, const QString &dir, const QStri const QModelIndex mapped_index = proxy_model->mapFromSource(created_object); ui->listView->setCurrentIndex(mapped_index); delete new_system; + modelDataChange(); }); } @@ -738,10 +787,10 @@ VMManagerMain::deleteSystem(VMManagerSystem *sysconfig) if (vm_model->rowCount(QModelIndex()) <= 0) { /* no machines left - get rid of the last machine's leftovers */ - ui->detailsArea->layout()->removeWidget(vm_details); - delete vm_details; - vm_details = new VMManagerDetails(); - ui->detailsArea->layout()->addWidget(vm_details); + selected_sysconfig = new VMManagerSystem(); + vm_details->reset(); + /* tell the mainwindow to disable the toolbar buttons */ + emit selectionOrStateChanged(nullptr); } } } @@ -815,6 +864,15 @@ VMManagerMain::modelDataChange() emit updateStatusRight(machineCountString(states)); } +void +VMManagerMain::vmStateChange() +{ + if (!currentSelectionIsValid()) + return; + + emit selectionOrStateChanged(selected_sysconfig); +} + void VMManagerMain::onPreferencesUpdated() { @@ -834,6 +892,7 @@ VMManagerMain::onLanguageUpdated() { vm_model->refreshConfigs(); modelDataChange(); + ui->searchBar->setPlaceholderText(tr("Search")); /* Hack to work around details widgets not being re-translatable without going through layers of abstraction */ ui->detailsArea->layout()->removeWidget(vm_details); diff --git a/src/qt/qt_vmmanager_main.hpp b/src/qt/qt_vmmanager_main.hpp index b08939d1c23..f313fbb042c 100644 --- a/src/qt/qt_vmmanager_main.hpp +++ b/src/qt/qt_vmmanager_main.hpp @@ -56,17 +56,19 @@ class VMManagerMain final : public QWidget { Settings, }; signals: - void selectionChanged(const QModelIndex ¤tSelection, QProcess::ProcessState processState); + void selectionOrStateChanged(VMManagerSystem *sysconfig); void updateStatusLeft(const QString &text); void updateStatusRight(const QString &text); public slots: + void reload(); void startButtonPressed() const; void settingsButtonPressed(); void restartButtonPressed() const; void pauseButtonPressed() const; void shutdownRequestButtonPressed() const; void shutdownForceButtonPressed() const; + void cadButtonPressed() const; void searchSystems(const QString &text) const; void newMachineWizard(); void updateGlobalSettings(); @@ -83,7 +85,6 @@ public slots: #ifdef Q_OS_WINDOWS void onDarkModeUpdated(); #endif - void onConfigUpdated(const QString &uuid); int getActiveMachineCount(); QList getPaneSizes() const; @@ -106,7 +107,6 @@ public slots: // const QItemSelection &deselected); void currentSelectionChanged(const QModelIndex ¤t, const QModelIndex &previous); - void refresh(); void updateDisplayName(const QModelIndex &index); void loadSettings(); [[nodiscard]] bool currentSelectionIsValid() const; @@ -116,6 +116,7 @@ public slots: #endif void showTextFileContents(const QString &title, const QString &path); private slots: + void vmStateChange(); #if EMU_BUILD_NUM != 0 void backgroundUpdateCheckComplete(const UpdateCheck::UpdateResult &result); void backgroundUpdateCheckError(const QString &errorMsg); diff --git a/src/qt/qt_vmmanager_main.ui b/src/qt/qt_vmmanager_main.ui index 566cea862b9..a79045aac7f 100644 --- a/src/qt/qt_vmmanager_main.ui +++ b/src/qt/qt_vmmanager_main.ui @@ -60,6 +60,19 @@ 0 + + + + Qt::ClickFocus + + + Search + + + true + + + @@ -76,19 +89,6 @@ - - - - Qt::ClickFocus - - - Search - - - true - - - diff --git a/src/qt/qt_vmmanager_mainwindow.cpp b/src/qt/qt_vmmanager_mainwindow.cpp index 0e44e6a8ca9..17bd898bda3 100644 --- a/src/qt/qt_vmmanager_mainwindow.cpp +++ b/src/qt/qt_vmmanager_mainwindow.cpp @@ -24,9 +24,6 @@ #include "qt_progsettings.hpp" #include "qt_util.hpp" -#include -#include -#include #include #include @@ -49,8 +46,11 @@ VMManagerMainWindow:: vmm_main_window = this; + runIcon = QIcon(":/menuicons/qt/icons/run.ico"); + pauseIcon = QIcon(":/menuicons/qt/icons/pause.ico"); + // Connect signals from the VMManagerMain widget - connect(vmm, &VMManagerMain::selectionChanged, this, &VMManagerMainWindow::vmmSelectionChanged); + connect(vmm, &VMManagerMain::selectionOrStateChanged, this, &VMManagerMainWindow::vmmStateChanged); setWindowTitle(tr("%1 VM Manager").arg(EMU_NAME)); setCentralWidget(vmm); @@ -61,6 +61,7 @@ VMManagerMainWindow:: connect(ui->actionSettings, &QAction::triggered, vmm, &VMManagerMain::settingsButtonPressed); connect(ui->actionHard_Reset, &QAction::triggered, vmm, &VMManagerMain::restartButtonPressed); connect(ui->actionForce_Shutdown, &QAction::triggered, vmm, &VMManagerMain::shutdownForceButtonPressed); + connect(ui->actionCtrl_Alt_Del, &QAction::triggered, vmm, &VMManagerMain::cadButtonPressed); // Set up menu actions // (Disable this if the EMU_BUILD_NUM == 0) @@ -70,48 +71,22 @@ VMManagerMainWindow:: connect(ui->actionCheck_for_updates, &QAction::triggered, this, &VMManagerMainWindow::checkForUpdatesTriggered); #endif - // TODO: Remove all of this (all the way to END REMOVE) once certain the search will no longer be in the toolbar. - // BEGIN REMOVE - // Everything is still setup here for it but it is all hidden. None of it will be - // needed if the search stays in VMManagerMain - ui->actionStartPause->setEnabled(true); - ui->actionStartPause->setIcon(QIcon(":/menuicons/qt/icons/run.ico")); + // Set up the toolbar + ui->actionStartPause->setEnabled(false); + ui->actionStartPause->setIcon(runIcon); ui->actionStartPause->setText(tr("Start")); ui->actionStartPause->setToolTip(tr("Start")); ui->actionHard_Reset->setEnabled(false); ui->actionForce_Shutdown->setEnabled(false); ui->actionCtrl_Alt_Del->setEnabled(false); + ui->actionSettings->setEnabled(false); - const auto searchBar = new QLineEdit(); - searchBar->setMinimumWidth(150); - searchBar->setPlaceholderText(tr("Search")); - searchBar->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); - searchBar->setClearButtonEnabled(true); - // Spacer to make the search go all the way to the right - const auto spacer = new QWidget(); - spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - ui->toolBar->addWidget(spacer); - ui->toolBar->addWidget(searchBar); - // Connect signal for search - connect(searchBar, &QLineEdit::textChanged, vmm, &VMManagerMain::searchSystems); // Preferences connect(ui->actionPreferences, &QAction::triggered, this, &VMManagerMainWindow::preferencesTriggered); - // Create a completer for the search bar - auto *completer = new QCompleter(this); - completer->setCaseSensitivity(Qt::CaseInsensitive); - completer->setFilterMode(Qt::MatchContains); - // Get the completer list - const auto allStrings = vmm->getSearchCompletionList(); - // Set up the completer - auto *completerModel = new QStringListModel(allStrings, completer); - completer->setModel(completerModel); - searchBar->setCompleter(completer); #ifdef Q_OS_WINDOWS ui->toolBar->setBackgroundRole(QPalette::Light); #endif - ui->toolBar->setVisible(false); - // END REMOVE // Status bar widgets statusLeft->setAlignment(Qt::AlignLeft); @@ -131,6 +106,9 @@ VMManagerMainWindow:: { auto config = new VMManagerConfig(VMManagerConfig::ConfigType::General); + ui->actionHide_tool_bar->setChecked(!!config->getStringValue("hide_tool_bar").toInt()); + if (ui->actionHide_tool_bar->isChecked()) + ui->toolBar->setVisible(false); if (!!config->getStringValue("window_remember").toInt()) { QString coords = config->getStringValue("window_coordinates"); if (!coords.isEmpty()) { @@ -176,37 +154,67 @@ VMManagerMainWindow::~VMManagerMainWindow() = default; void -VMManagerMainWindow::vmmSelectionChanged(const QModelIndex ¤tSelection, const QProcess::ProcessState processState) const +VMManagerMainWindow::vmmStateChanged(const VMManagerSystem *sysconfig) const { - if (processState == QProcess::Running) { - ui->actionStartPause->setEnabled(true); - ui->actionStartPause->setIcon(QIcon(":/menuicons/qt/icons/pause.ico")); - ui->actionStartPause->setText(tr("Pause")); - ui->actionStartPause->setToolTip(tr("Pause")); + if (sysconfig == nullptr) { + // This doubles both as a safety check and a way to disable + // all machine-related buttons when no machines are present + ui->actionStartPause->setEnabled(false); + ui->actionSettings->setEnabled(false); + ui->actionHard_Reset->setEnabled(false); + ui->actionForce_Shutdown->setEnabled(false); + ui->actionCtrl_Alt_Del->setEnabled(false); + return; + } + const bool running = sysconfig->process->state() == QProcess::ProcessState::Running; + + if (running) { + if (sysconfig->getProcessStatus() == VMManagerSystem::ProcessStatus::Running) { + ui->actionStartPause->setIcon(pauseIcon); + ui->actionStartPause->setText(tr("&Pause")); + ui->actionStartPause->setToolTip(tr("Pause")); + ui->actionStartPause->setIconText(tr("Pause")); + } else { + ui->actionStartPause->setIcon(runIcon); + ui->actionStartPause->setText(tr("&Continue")); + ui->actionStartPause->setToolTip(tr("Continue")); + ui->actionStartPause->setIconText(tr("Continue")); + } disconnect(ui->actionStartPause, &QAction::triggered, vmm, &VMManagerMain::startButtonPressed); + disconnect(ui->actionStartPause, &QAction::triggered, vmm, &VMManagerMain::pauseButtonPressed); connect(ui->actionStartPause, &QAction::triggered, vmm, &VMManagerMain::pauseButtonPressed); - ui->actionHard_Reset->setEnabled(true); - ui->actionForce_Shutdown->setEnabled(true); - ui->actionCtrl_Alt_Del->setEnabled(true); } else { - ui->actionStartPause->setEnabled(true); - ui->actionStartPause->setIcon(QIcon(":/menuicons/qt/icons/run.ico")); - ui->actionStartPause->setText(tr("Start")); + ui->actionStartPause->setIcon(runIcon); + ui->actionStartPause->setText(tr("&Start")); ui->actionStartPause->setToolTip(tr("Start")); + ui->actionStartPause->setIconText(tr("Start")); disconnect(ui->actionStartPause, &QAction::triggered, vmm, &VMManagerMain::pauseButtonPressed); + disconnect(ui->actionStartPause, &QAction::triggered, vmm, &VMManagerMain::startButtonPressed); connect(ui->actionStartPause, &QAction::triggered, vmm, &VMManagerMain::startButtonPressed); - ui->actionHard_Reset->setEnabled(false); - ui->actionForce_Shutdown->setEnabled(false); - ui->actionCtrl_Alt_Del->setEnabled(false); } + + ui->actionStartPause->setEnabled(!sysconfig->window_obscured); + ui->actionSettings->setEnabled(!sysconfig->window_obscured); + ui->actionHard_Reset->setEnabled(sysconfig->window_obscured ? false : running); + ui->actionForce_Shutdown->setEnabled(sysconfig->window_obscured ? false : running); + ui->actionCtrl_Alt_Del->setEnabled(sysconfig->window_obscured ? false : running); } void VMManagerMainWindow::preferencesTriggered() { - const auto prefs = new VMManagerPreferences(); + bool machinesRunning = (vmm->getActiveMachineCount() > 0); + auto old_vmm_path = QString(vmm_path_cfg); + const auto prefs = new VMManagerPreferences(this, machinesRunning); if (prefs->exec() == QDialog::Accepted) { emit preferencesUpdated(); updateLanguage(); + + auto new_vmm_path = QString(vmm_path_cfg); + if (!machinesRunning && (new_vmm_path != old_vmm_path)) { + qDebug() << "Machine path changed: old path " << old_vmm_path << ", new path " << new_vmm_path; + strncpy(vmm_path, vmm_path_cfg, sizeof(vmm_path)); + vmm->reload(); + } } } @@ -224,6 +232,7 @@ VMManagerMainWindow::saveSettings() const const auto currentSelection = vmm->getCurrentSelection(); const auto config = new VMManagerConfig(VMManagerConfig::ConfigType::General); config->setStringValue("last_selection", currentSelection); + config->setStringValue("hide_tool_bar", (ui->toolBar->isVisible() ? "0" : "1")); if (!!config->getStringValue("window_remember").toInt()) { config->setStringValue("window_coordinates", QString::asprintf("%i, %i, %i, %i", this->geometry().x(), this->geometry().y(), this->geometry().width(), this->geometry().height())); config->setStringValue("window_maximized", this->isMaximized() ? "1" : ""); @@ -271,7 +280,7 @@ VMManagerMainWindow::closeEvent(QCloseEvent *event) { int running = vmm->getActiveMachineCount(); if (running > 0) { - QMessageBox warningbox(QMessageBox::Icon::Warning, tr("%1 VM Manager").arg(EMU_NAME), tr("%1 machine(s) are currently active. Are you sure you want to exit the VM manager anyway?").arg(running), QMessageBox::Yes | QMessageBox::No, this); + QMessageBox warningbox(QMessageBox::Icon::Warning, tr("%1 VM Manager").arg(EMU_NAME), tr("%n machine(s) are currently active. Are you sure you want to exit the VM manager anyway?", "", running), QMessageBox::Yes | QMessageBox::No, this); warningbox.exec(); if (warningbox.result() == QMessageBox::No) { event->ignore(); @@ -294,6 +303,15 @@ VMManagerMainWindow::setStatusRight(const QString &text) const statusRight->setText(text); } +void +VMManagerMainWindow::on_actionHide_tool_bar_triggered() +{ + const auto config = new VMManagerConfig(VMManagerConfig::ConfigType::General); + int isHidden = config->getStringValue("hide_tool_bar").toInt(); + ui->toolBar->setVisible(!!isHidden); + config->setStringValue("hide_tool_bar", (isHidden ? "0" : "1")); +} + #if EMU_BUILD_NUM != 0 void VMManagerMainWindow::checkForUpdatesTriggered() diff --git a/src/qt/qt_vmmanager_mainwindow.hpp b/src/qt/qt_vmmanager_mainwindow.hpp index c0e06f551bb..5d96fa5b265 100644 --- a/src/qt/qt_vmmanager_mainwindow.hpp +++ b/src/qt/qt_vmmanager_mainwindow.hpp @@ -45,6 +45,8 @@ class VMManagerMainWindow final : public QMainWindow { void saveSettings() const; QLabel *statusLeft; QLabel *statusRight; + QIcon runIcon; + QIcon pauseIcon; public slots: void setStatusLeft(const QString &text) const; @@ -55,7 +57,8 @@ public slots: #endif private slots: - void vmmSelectionChanged(const QModelIndex ¤tSelection, QProcess::ProcessState processState) const; + void vmmStateChanged(const VMManagerSystem *sysconfig) const; + void on_actionHide_tool_bar_triggered(); void preferencesTriggered(); #if EMU_BUILD_NUM != 0 void checkForUpdatesTriggered(); diff --git a/src/qt/qt_vmmanager_mainwindow.ui b/src/qt/qt_vmmanager_mainwindow.ui index c45e83741b2..fbaeecf0ff0 100644 --- a/src/qt/qt_vmmanager_mainwindow.ui +++ b/src/qt/qt_vmmanager_mainwindow.ui @@ -11,7 +11,7 @@ - 86Box VM Manager + 86Box VM Manager @@ -23,6 +23,9 @@ 21 + + Qt::PreventContextMenu + &Tools @@ -38,6 +41,12 @@ + + + &View + + + &Help @@ -47,6 +56,7 @@ + @@ -56,22 +66,25 @@ true - toolBar + toolBar false + + Qt::PreventContextMenu + Qt::TopToolBarArea - 16 - 16 + 32 + 32 - Qt::ToolButtonIconOnly + Qt::ToolButtonTextUnderIcon TopToolBarArea @@ -88,9 +101,6 @@ - - true - :/menuicons/qt/icons/run.ico:/menuicons/qt/icons/run.ico @@ -101,8 +111,8 @@ Start - - false + + Start @@ -116,8 +126,8 @@ Hard reset - - false + + Hard reset @@ -134,12 +144,12 @@ Force shutdown + + Force shutdown + true - - false - @@ -155,14 +165,11 @@ Ctrl+Alt+Del - - false - - - false + + Ctrl+Alt+Del - - false + + true @@ -171,59 +178,52 @@ :/menuicons/qt/icons/settings.ico:/menuicons/qt/icons/settings.ico - &Settings... + &Settings… - Settings... + Settings… + + + Settings QAction::NoRole - - false - - :/settings/qt/icons/86Box-yellow.ico:/settings/qt/icons/86Box-yellow.ico + :/menuicons/qt/icons/new_vm.ico:/menuicons/qt/icons/new_vm.ico - &New machine... + &New machine… - New machine... + New machine… - - - - &Preferences... - - - Preferences... - - - QAction::PreferencesRole + + New machine - + true - - - :/menuicons/qt/icons/run.ico:/menuicons/qt/icons/run.ico + + Hide &toolbar + + - &Start + &Preferences… - - false + + QAction::PreferencesRole - &Check for updates... + &Check for updates… @@ -236,12 +236,12 @@ - &Documentation... + &Documentation… - &About 86Box... + &About 86Box… QAction::AboutRole diff --git a/src/qt/qt_vmmanager_preferences.cpp b/src/qt/qt_vmmanager_preferences.cpp index eb4f20d3362..df30aec6caf 100644 --- a/src/qt/qt_vmmanager_preferences.cpp +++ b/src/qt/qt_vmmanager_preferences.cpp @@ -29,11 +29,12 @@ extern WindowsDarkModeFilter *vmm_dark_mode_filter; extern "C" { #include <86box/86box.h> #include <86box/config.h> +#include <86box/plat.h> #include <86box/version.h> } VMManagerPreferences:: - VMManagerPreferences(QWidget *parent) + VMManagerPreferences(QWidget *parent, bool machinesRunning) : ui(new Ui::VMManagerPreferences) { ui->setupUi(this); @@ -50,6 +51,13 @@ VMManagerPreferences:: ui->systemDirectory->setText(QDir::toNativeSeparators(QDir(vmm_path).path())); } + if (machinesRunning) { + ui->systemDirectory->setEnabled(false); + ui->dirSelectButton->setEnabled(false); + ui->pushButtonDefaultSystemDir->setEnabled(false); + ui->dirSelectButton->setToolTip(tr("To change the system directory, stop all running machines.")); + } + ui->comboBoxLanguage->setItemData(0, 0); for (int i = 1; i < ProgSettings::languages.length(); i++) { ui->comboBoxLanguage->addItem(ProgSettings::languages[i].second, i); @@ -59,7 +67,6 @@ VMManagerPreferences:: } ui->comboBoxLanguage->model()->sort(Qt::AscendingOrder); - // TODO: Defaults #if EMU_BUILD_NUM != 0 const auto configUpdateCheck = config->getStringValue("update_check").toInt(); ui->updateCheckBox->setChecked(configUpdateCheck); @@ -92,6 +99,14 @@ VMManagerPreferences::chooseDirectoryLocation() ui->systemDirectory->setText(QDir::toNativeSeparators(directory)); } +void +VMManagerPreferences::on_pushButtonDefaultSystemDir_released() +{ + char temp[1024]; + plat_get_vmm_dir(temp, sizeof(temp)); + ui->systemDirectory->setText(QDir::toNativeSeparators(QDir(temp).path())); +} + void VMManagerPreferences::on_pushButtonLanguage_released() { diff --git a/src/qt/qt_vmmanager_preferences.hpp b/src/qt/qt_vmmanager_preferences.hpp index 4215eb76892..cbb7c5f6126 100644 --- a/src/qt/qt_vmmanager_preferences.hpp +++ b/src/qt/qt_vmmanager_preferences.hpp @@ -26,7 +26,7 @@ QT_END_NAMESPACE class VMManagerPreferences final : public QDialog { Q_OBJECT public: - explicit VMManagerPreferences(QWidget *parent = nullptr); + explicit VMManagerPreferences(QWidget *parent = nullptr, bool machinesRunning = false); ~VMManagerPreferences() override; private: @@ -34,6 +34,7 @@ class VMManagerPreferences final : public QDialog { QString settingsFile; private slots: void chooseDirectoryLocation(); + void on_pushButtonDefaultSystemDir_released(); void on_pushButtonLanguage_released(); protected: diff --git a/src/qt/qt_vmmanager_preferences.ui b/src/qt/qt_vmmanager_preferences.ui index 7206b79bfd9..a4d526f8c17 100644 --- a/src/qt/qt_vmmanager_preferences.ui +++ b/src/qt/qt_vmmanager_preferences.ui @@ -56,6 +56,36 @@ + + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Default + + + + + @@ -170,6 +200,7 @@ dirSelectButton + pushButtonDefaultSystemDir comboBoxLanguage pushButtonLanguage rememberSizePositionCheckBox diff --git a/src/qt/qt_vmmanager_system.cpp b/src/qt/qt_vmmanager_system.cpp index 5038732d101..eb91ef2203d 100644 --- a/src/qt/qt_vmmanager_system.cpp +++ b/src/qt/qt_vmmanager_system.cpp @@ -124,7 +124,7 @@ VMManagerSystem::scanForConfigs(QWidget *parent, const QString &searchPath) QProgressDialog progDialog(parent); unsigned int found = 0; progDialog.setCancelButton(nullptr); - progDialog.setWindowTitle(tr("Searching for VMs...")); + progDialog.setWindowTitle(tr("Searching for VMs…")); progDialog.setMinimumDuration(0); progDialog.setValue(0); progDialog.setMinimum(0); @@ -305,15 +305,11 @@ void VMManagerSystem::generateSearchTerms() { searchTerms.clear(); - for (const auto &config_key : config_hash.keys()) { - // searchTerms.append(config_hash[config_key].values()); - // brute force temporarily don't add paths - for (const auto &value : config_hash[config_key].values()) { - if (!value.startsWith("/")) - searchTerms.append(value); - } - } - searchTerms.append(display_table.values()); + for (const auto &value : display_table.values()) + if (value.contains(";")) + searchTerms.append(value.split(';')); + else + searchTerms.append(value); searchTerms.append(displayName); searchTerms.append(config_name); QRegularExpression whitespaceRegex("\\s+"); @@ -394,9 +390,8 @@ VMManagerSystem::has86BoxBinary() } void -VMManagerSystem::launchMainProcess() +VMManagerSystem::launch86Box(bool settings) { - if (!has86BoxBinary()) { qWarning("No binary found! returning"); return; @@ -410,22 +405,31 @@ VMManagerSystem::launchMainProcess() return; } } - // If the system is already running, bring it to front + // If the system is already running, bring it to front or instruct it to show settings if (process->processId() != 0) { #ifdef Q_OS_WINDOWS if (this->id) { SetForegroundWindow((HWND) this->id); } #endif + if (settings) + socket_server->serverSendMessage(VMManagerProtocol::ManagerMessage::ShowSettings); return; } + + // Otherwise, launch the system setProcessEnvVars(); + window_obscured = settings; QString program = main_binary.filePath(); QStringList args; args << "--vmpath" << config_dir; args << "--vmname" << displayName; + if (settings) + args << "--settings"; if (rom_path[0] != '\0') args << "--rompath" << QString(rom_path); + if (asset_path[0] != '\0') + args << "--assetpath" << QString(asset_path); if (global_cfg_overridden) args << "--global" << QString(global_cfg_path); if (!hook_enabled) @@ -440,78 +444,30 @@ VMManagerSystem::launchMainProcess() process->start(); updateTimestamp(); + disconnect(process, QOverload::of(&QProcess::finished), nullptr, nullptr); connect(process, QOverload::of(&QProcess::finished), [=](const int exitCode, const QProcess::ExitStatus exitStatus) { if (exitCode != 0 || exitStatus != QProcess::NormalExit) { - qInfo().nospace().noquote() << "Abnormal program termination while launching main process: exit code " << exitCode << ", exit status " << exitStatus; + qInfo().nospace().noquote() << "Abnormal program termination while launching system: exit code " << exitCode << ", exit status " << exitStatus; QMessageBox::critical(this, tr("Virtual machine crash"), - tr("The virtual machine \"%1\"'s process has unexpectedly terminated with exit code %2.").arg(displayName, QString::number(exitCode))); + tr("The virtual machine \"%1\"'s process has unexpectedly terminated with exit code %2.").arg(displayName, QString("%1 (0x%2)").arg(QString::number(exitCode), QString::number(exitCode, 16)))); return; } + + configurationChangeReceived(); }); } void VMManagerSystem::startButtonPressed() { - launchMainProcess(); + launch86Box(false); } void VMManagerSystem::launchSettings() { - if (!has86BoxBinary()) { - qWarning("No binary found! returning"); - return; - } - - // start the server first to get the socket name - if (!serverIsRunning) { - if (!startServer()) { - // FIXME: Better error handling - qInfo("Failed to start VM Manager server"); - return; - } - } - - // If the system is already running, instruct it to show settings - if (process->processId() != 0) { -#ifdef Q_OS_WINDOWS - if (this->id) { - SetForegroundWindow((HWND) this->id); - } -#endif - socket_server->serverSendMessage(VMManagerProtocol::ManagerMessage::ShowSettings); - return; - } - - // Otherwise, launch the system with the settings parameter - setProcessEnvVars(); - window_obscured = true; - QString program = main_binary.filePath(); - QStringList open_command_args; - QStringList args; - args << "--vmpath" << config_dir << "--settings"; - if (rom_path[0] != '\0') - args << "--rompath" << QString(rom_path); - if (global_cfg_overridden) - args << "--global" << QString(global_cfg_path); - process->setProgram(program); - process->setArguments(args); - qDebug() << Q_FUNC_INFO << " Full Command:" << process->program() << " " << process->arguments(); - process->start(); - - connect(process, QOverload::of(&QProcess::finished), - [=](const int exitCode, const QProcess::ExitStatus exitStatus) { - if (exitCode != 0 || exitStatus != QProcess::NormalExit) { - qInfo().nospace().noquote() << "Abnormal program termination while launching settings: exit code " << exitCode << ", exit status " << exitStatus; - QMessageBox::critical(this, tr("Virtual machine crash"), - tr("The virtual machine \"%1\"'s process has unexpectedly terminated with exit code %2.").arg(displayName, QString("%1 (0x%2)").arg(QString::number(exitCode), QString::number(exitCode, 16)))); - return; - } - - configurationChangeReceived(); - }); + launch86Box(true); } void @@ -565,14 +521,11 @@ VMManagerSystem::setupVars() auto machine_name = QString(); int i = 0; int ram_granularity = 0; + int ci = machine_get_machine_from_internal_name(machine_config["machine"].toUtf8()); // Machine - for (int ci = 0; ci < machine_count(); ++ci) { - if (machine_available(ci)) { - if (machines[ci].internal_name == machine_config["machine"]) { - machine_name = machines[ci].name; - ram_granularity = machines[ci].ram.step; - } - } + if (ci != -1 && machine_available(ci)) { + machine_name = machines[ci].name; + ram_granularity = machines[ci].ram.step; } display_table[VMManager::Display::Name::Machine] = machine_name; @@ -939,7 +892,7 @@ VMManagerSystem::setupVars() net_type = "SLiRP"; else if (net_type == "pcap") net_type = "PCap"; - else if (net_type == "nmswitch") + else if ((net_type == "nlswitch") || (net_type == "nmswitch")) net_type = tr("Local Switch"); else if (net_type == "nrswitch") net_type = tr("Remote Switch"); @@ -1239,8 +1192,9 @@ void VMManagerSystem::configurationChangeReceived() { reloadConfig(); - emit configurationChanged(this->uuid); + emit configurationChanged(this); } + void VMManagerSystem::reloadConfig() { diff --git a/src/qt/qt_vmmanager_system.hpp b/src/qt/qt_vmmanager_system.hpp index 96c794df3f3..ca79f4e3ce9 100644 --- a/src/qt/qt_vmmanager_system.hpp +++ b/src/qt/qt_vmmanager_system.hpp @@ -120,7 +120,7 @@ class VMManagerSystem : public QWidget { [[nodiscard]] bool isProcessRunning() const; [[nodiscard]] qint64 processId() const; public slots: - void launchMainProcess(); + void launch86Box(bool settings = false); void launchSettings(); void startButtonPressed(); void restartButtonPressed(); @@ -138,7 +138,6 @@ public slots: QProcess *process = new QProcess(); bool window_obscured; - bool config_signal_connected = false; QString getDisplayValue(VMManager::Display::Name key); QFileInfoList getScreenshots(); @@ -158,7 +157,7 @@ public slots: void windowStatusChanged(); void itemDataChanged(); void clientProcessStatusChanged(); - void configurationChanged(const QString &uuid); + void configurationChanged(VMManagerSystem *sysconfig); void globalConfigurationChanged(); private: diff --git a/src/qt/qt_vulkanrenderer.cpp b/src/qt/qt_vulkanrenderer.cpp index be588a8d2a0..d34757ba7c9 100644 --- a/src/qt/qt_vulkanrenderer.cpp +++ b/src/qt/qt_vulkanrenderer.cpp @@ -428,8 +428,6 @@ VulkanRenderer2::updateSamplers() void VulkanRenderer2::initResources() { - qDebug("initResources"); - VkDevice dev = m_window->device(); m_devFuncs = m_window->vulkanInstance()->deviceFunctions(dev); @@ -811,8 +809,6 @@ VulkanRenderer2::initResources() void VulkanRenderer2::initSwapChainResources() { - qDebug("initSwapChainResources"); - // Projection matrix m_proj = m_window->clipCorrectionMatrix(); // adjust for Vulkan-OpenGL clip space differences } @@ -820,14 +816,11 @@ VulkanRenderer2::initSwapChainResources() void VulkanRenderer2::releaseSwapChainResources() { - qDebug("releaseSwapChainResources"); } void VulkanRenderer2::releaseResources() { - qDebug("releaseResources"); - VkDevice dev = m_window->device(); if (m_sampler) { diff --git a/src/qt/qt_vulkanwindowrenderer.cpp b/src/qt/qt_vulkanwindowrenderer.cpp index 79dbc8f873e..c27d382a50b 100644 --- a/src/qt/qt_vulkanwindowrenderer.cpp +++ b/src/qt/qt_vulkanwindowrenderer.cpp @@ -32,6 +32,8 @@ ****************************************************************************/ #include "qt_vulkanwindowrenderer.hpp" +#include +#include #include #include @@ -46,6 +48,8 @@ extern "C" { # include <86box/86box.h> +# include <86box/path.h> +# include <86box/plat.h> # include <86box/video.h> } # if 0 @@ -861,6 +865,8 @@ VulkanWindowRenderer::event(QEvent *event) return res; } +extern void take_screenshot_clipboard_monitor(int sx, int sy, int sw, int sh, int i); + void VulkanWindowRenderer::onBlit(int buf_idx, int x, int y, int w, int h) { @@ -873,6 +879,40 @@ VulkanWindowRenderer::onBlit(int buf_idx, int x, int y, int w, int h) this->pixelRatio = devicePixelRatio(); onResize(this->width(), this->height()); } + + if (monitors[r_monitor_index].mon_screenshots) { + char path[1024]; + char fn[256]; + + memset(fn, 0, sizeof(fn)); + memset(path, 0, sizeof(path)); + + path_append_filename(path, usr_path, SCREENSHOT_PATH); + + if (!plat_dir_check(path)) + plat_dir_create(path); + + path_slash(path); + strcat(path, "Monitor_"); + snprintf(&path[strlen(path)], 42, "%d_", r_monitor_index + 1); + + plat_tempfile(fn, NULL, (char *) ".png"); + strcat(path, fn); + + QImage image = this->grab(); + image.rgbSwapped().save(path, "png"); + monitors[r_monitor_index].mon_screenshots--; + } + if (monitors[r_monitor_index].mon_screenshots_clipboard) { + QImage image = this->grab(); + image = image.rgbSwapped(); + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setImage(image, QClipboard::Clipboard); + monitors[r_monitor_index].mon_screenshots_clipboard--; + } + if (monitors[r_monitor_index].mon_screenshots_raw_clipboard) { + take_screenshot_clipboard_monitor(x, y, w, h, r_monitor_index); + } } uint32_t diff --git a/src/qt/qt_winrawinputfilter.cpp b/src/qt/qt_winrawinputfilter.cpp index d40f4cdd688..5332cacbbcb 100644 --- a/src/qt/qt_winrawinputfilter.cpp +++ b/src/qt/qt_winrawinputfilter.cpp @@ -526,13 +526,13 @@ WindowsRawInputFilter::mouse_handle(RAWMOUSE *raw) mouse_set_buttons_ex(b); if (state.usButtonFlags & RI_MOUSE_WHEEL) { - delta_z = (SHORT) state.usButtonData / 120; + delta_z = (SHORT) state.usButtonData; mouse_set_z(delta_z); } else delta_z = 0; if (state.usButtonFlags & RI_MOUSE_HWHEEL) { - delta_w = (SHORT) state.usButtonData / 120; + delta_w = (SHORT) state.usButtonData; mouse_set_w(delta_w); } else delta_w = 0; diff --git a/src/qt/win_serial_passthrough.c b/src/qt/win_serial_passthrough.c index 58ebb7fcb0f..ab2d8a9ee3b 100644 --- a/src/qt/win_serial_passthrough.c +++ b/src/qt/win_serial_passthrough.c @@ -215,7 +215,7 @@ open_pseudo_terminal(serial_passthrough_t *dev) char ascii_pipe_name[1024] = { 0 }; strncpy(ascii_pipe_name, dev->named_pipe, sizeof(ascii_pipe_name)); ascii_pipe_name[1023] = '\0'; - dev->master_fd = (intptr_t) CreateNamedPipeA(ascii_pipe_name, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT, 1, 65536, 65536, NMPWAIT_USE_DEFAULT_WAIT, NULL); + dev->master_fd = (intptr_t) CreateNamedPipeA(ascii_pipe_name, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT, PIPE_UNLIMITED_INSTANCES, 65536, 65536, NMPWAIT_USE_DEFAULT_WAIT, NULL); if (dev->master_fd == (intptr_t) INVALID_HANDLE_VALUE) { wchar_t errorMsg[1024] = { 0 }; wchar_t finalMsg[1024] = { 0 }; diff --git a/src/qt_resources.qrc b/src/qt_resources.qrc index 78153d3ff80..4b069cb3f18 100644 --- a/src/qt_resources.qrc +++ b/src/qt_resources.qrc @@ -68,6 +68,13 @@ qt/icons/send_cad.ico qt/icons/send_cae.ico qt/icons/settings.ico + qt/icons/interpreter.ico + qt/icons/recompiler.ico + qt/icons/new_vm.ico + qt/icons/take_screenshot.ico + qt/icons/take_raw_screenshot.ico + qt/icons/copy_screenshot.ico + qt/icons/copy_raw_screenshot.ico qt/icons/warning.ico diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt index a6a9b691aa7..3f6b1ef6202 100644 --- a/src/sound/CMakeLists.txt +++ b/src/sound/CMakeLists.txt @@ -31,6 +31,7 @@ add_library(snd OBJECT snd_ps1.c snd_adlib.c snd_adlibgold.c + snd_ad1816.c snd_ad1848.c snd_audiopci.c snd_azt2316a.c @@ -53,6 +54,7 @@ add_library(snd OBJECT snd_opl_esfm.c snd_ymf701.c snd_ymf71x.c + sound_util.c ) # TODO: Should platform-specific audio driver be here? diff --git a/src/sound/audio4.c b/src/sound/audio4.c index 060e574e6fd..48b0a6ce1db 100644 --- a/src/sound/audio4.c +++ b/src/sound/audio4.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -37,17 +38,18 @@ #define I_WT 2 #define I_CD 3 #define I_FDD 4 -#define I_MIDI 5 +#define I_HDD 5 +#define I_MIDI 6 -static int audio[6] = {-1, -1, -1, -1, -1, -1}; +static int audio[7] = {-1, -1, -1, -1, -1, -1, -1}; +extern bool fast_forward; #ifdef USE_NEW_API -static struct audio_swpar info[5]; +static struct audio_swpar info[7]; #else -static audio_info_t info[6]; +static audio_info_t info[7]; #endif -static int freqs[6] = {SOUND_FREQ, MUSIC_FREQ, WT_FREQ, CD_FREQ, SOUND_FREQ, 0}; - +static int freqs[7] = {SOUND_FREQ, MUSIC_FREQ, WT_FREQ, CD_FREQ, SOUND_FREQ, SOUND_FREQ, 0}; void closeal(void) { @@ -104,7 +106,7 @@ givealbuffer_common(const void *buf, const uint8_t src, const int size) double gain; int target_rate; - if(audio[src] == -1) + if(audio[src] == -1 || fast_forward) return; gain = sound_muted ? 0.0 : pow(10.0, (double) sound_gain / 20.0); @@ -173,6 +175,12 @@ givealbuffer_fdd(const void *buf, const uint32_t size) givealbuffer_common(buf, I_FDD, (int) size); } +void +givealbuffer_hdd(const void *buf, const uint32_t size) +{ + givealbuffer_common(buf, I_HDD, (int) size); +} + void givealbuffer_midi(const void *buf, const uint32_t size) { diff --git a/src/sound/midi_fluidsynth.c b/src/sound/midi_fluidsynth.c index 1afefd90568..577c053678b 100644 --- a/src/sound/midi_fluidsynth.c +++ b/src/sound/midi_fluidsynth.c @@ -16,6 +16,7 @@ #include <86box/thread.h> #include <86box/sound.h> #include <86box/plat_unused.h> +#include <86box/plat.h> #define RENDER_RATE 100 #define BUFFER_SEGMENTS 10 @@ -154,6 +155,9 @@ fluidsynth_init(UNUSED(const device_t *info)) { fluidsynth_t *data = &fsdev; midi_device_t *dev; +#ifdef _WIN32 + char path[4096] = { 0 }; +#endif memset(data, 0, sizeof(fluidsynth_t)); @@ -170,6 +174,17 @@ fluidsynth_init(UNUSED(const device_t *info)) if (!sound_font || sound_font[0] == 0) sound_font = (access("/usr/share/sounds/sf2/FluidR3_GM.sf2", F_OK) == 0 ? "/usr/share/sounds/sf2/FluidR3_GM.sf2" : (access("/usr/share/soundfonts/default.sf2", F_OK) == 0 ? "/usr/share/soundfonts/default.sf2" : "")); +#elif defined _WIN32 + if (!sound_font || sound_font[0] == 0) { + // FluidSynth 2.5.x and later supports DLS without libinstpatch. + int major, minor, patch; + fluid_version(&major, &minor, &patch); + if ((major == 2 && minor >= 5) || (major >= 3)) { + plat_get_system_directory(path); + strcat(path, "\\system32\\drivers\\gm.dls"); + sound_font = plat_file_check(path) ? path : ""; + } + } #endif data->sound_font = fluid_synth_sfload(data->synth, sound_font, 1); diff --git a/src/sound/openal.c b/src/sound/openal.c index d163150af1c..399e4ac8e24 100644 --- a/src/sound/openal.c +++ b/src/sound/openal.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #undef AL_API #undef ALC_API @@ -40,15 +41,17 @@ #define I_WT 2 #define I_CD 3 #define I_FDD 4 -#define I_MIDI 5 +#define I_HDD 5 +#define I_MIDI 6 ALuint buffers[4]; /* front and back buffers */ ALuint buffers_music[4]; /* front and back buffers */ ALuint buffers_wt[4]; /* front and back buffers */ ALuint buffers_cd[4]; /* front and back buffers */ ALuint buffers_fdd[4]; /* front and back buffers */ +ALuint buffers_hdd[4]; /* front and back buffers */ ALuint buffers_midi[4]; /* front and back buffers */ -static ALuint source[6]; /* audio source - CHANGED FROM 5 TO 6 */ +static ALuint source[7]; /* audio sources */ static int midi_freq = 44100; static int midi_buf_size = 4410; @@ -105,9 +108,10 @@ closeal(void) alSourceStopv(sources, source); alDeleteSources(sources, source); - if (sources >= 6) + if (sources >= 7) alDeleteBuffers(4, buffers_midi); alDeleteBuffers(4, buffers_fdd); + alDeleteBuffers(4, buffers_hdd); alDeleteBuffers(4, buffers_cd); alDeleteBuffers(4, buffers_music); alDeleteBuffers(4, buffers); @@ -126,12 +130,14 @@ inital(void) float *cd_buf = NULL; float *midi_buf = NULL; float *fdd_buf = NULL; + float *hdd_buf = NULL; int16_t *buf_int16 = NULL; int16_t *music_buf_int16 = NULL; int16_t *wt_buf_int16 = NULL; int16_t *cd_buf_int16 = NULL; int16_t *midi_buf_int16 = NULL; int16_t *fdd_buf_int16 = NULL; + int16_t *hdd_buf_int16 = NULL; int init_midi = 0; @@ -146,13 +152,14 @@ inital(void) init_midi = 1; /* If the device is neither none, nor system MIDI, initialize the MIDI buffer and source, otherwise, do not. */ - sources = 5 + !!init_midi; + sources = 6 + !!init_midi; if (sound_is_float) { buf = (float *) calloc((BUFLEN << 1), sizeof(float)); music_buf = (float *) calloc((MUSICBUFLEN << 1), sizeof(float)); wt_buf = (float *) calloc((WTBUFLEN << 1), sizeof(float)); cd_buf = (float *) calloc((CD_BUFLEN << 1), sizeof(float)); fdd_buf = (float *) calloc((BUFLEN << 1), sizeof(float)); + hdd_buf = (float *) calloc((BUFLEN << 1), sizeof(float)); if (init_midi) midi_buf = (float *) calloc(midi_buf_size, sizeof(float)); } else { @@ -161,6 +168,7 @@ inital(void) wt_buf_int16 = (int16_t *) calloc((WTBUFLEN << 1), sizeof(int16_t)); cd_buf_int16 = (int16_t *) calloc((CD_BUFLEN << 1), sizeof(int16_t)); fdd_buf_int16 = (int16_t *) calloc((BUFLEN << 1), sizeof(int16_t)); + hdd_buf_int16 = (int16_t *) calloc((BUFLEN << 1), sizeof(int16_t)); if (init_midi) midi_buf_int16 = (int16_t *) calloc(midi_buf_size, sizeof(int16_t)); } @@ -168,18 +176,17 @@ inital(void) alGenBuffers(4, buffers); alGenBuffers(4, buffers_cd); alGenBuffers(4, buffers_fdd); + alGenBuffers(4, buffers_hdd); alGenBuffers(4, buffers_music); alGenBuffers(4, buffers_wt); if (init_midi) alGenBuffers(4, buffers_midi); - // Create sources: 0=main, 1=music, 2=wt, 3=cd, 4=fdd, 5=midi(optional) - alGenSources(sources, source); - + // Create sources: 0=main, 1=music, 2=wt, 3=cd, 4=fdd, 5=hdd, 6=midi(optional) if (init_midi) - alGenSources(5, source); + alGenSources(7, source); else - alGenSources(4, source); + alGenSources(6, source); alSource3f(source[I_NORMAL], AL_POSITION, 0.0f, 0.0f, 0.0f); alSource3f(source[I_NORMAL], AL_VELOCITY, 0.0f, 0.0f, 0.0f); @@ -210,7 +217,13 @@ inital(void) alSource3f(source[I_FDD], AL_DIRECTION, 0.0f, 0.0f, 0.0f); alSourcef(source[I_FDD], AL_ROLLOFF_FACTOR, 0.0f); alSourcei(source[I_FDD], AL_SOURCE_RELATIVE, AL_TRUE); - + + alSource3f(source[I_HDD], AL_POSITION, 0.0f, 0.0f, 0.0f); + alSource3f(source[I_HDD], AL_VELOCITY, 0.0f, 0.0f, 0.0f); + alSource3f(source[I_HDD], AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSourcef(source[I_HDD], AL_ROLLOFF_FACTOR, 0.0f); + alSourcei(source[I_HDD], AL_SOURCE_RELATIVE, AL_TRUE); + if (init_midi) { alSource3f(source[I_MIDI], AL_POSITION, 0.0f, 0.0f, 0.0f); alSource3f(source[I_MIDI], AL_VELOCITY, 0.0f, 0.0f, 0.0f); @@ -225,6 +238,7 @@ inital(void) memset(music_buf, 0, MUSICBUFLEN * 2 * sizeof(float)); memset(wt_buf, 0, WTBUFLEN * 2 * sizeof(float)); memset(fdd_buf, 0, BUFLEN * 2 * sizeof(float)); + memset(hdd_buf, 0, BUFLEN * 2 * sizeof(float)); if (init_midi) memset(midi_buf, 0, midi_buf_size * sizeof(float)); } else { @@ -233,6 +247,7 @@ inital(void) memset(music_buf_int16, 0, MUSICBUFLEN * 2 * sizeof(int16_t)); memset(wt_buf_int16, 0, WTBUFLEN * 2 * sizeof(int16_t)); memset(fdd_buf_int16, 0, BUFLEN * 2 * sizeof(int16_t)); + memset(hdd_buf_int16, 0, BUFLEN * 2 * sizeof(int16_t)); if (init_midi) memset(midi_buf_int16, 0, midi_buf_size * sizeof(int16_t)); } @@ -244,6 +259,7 @@ inital(void) alBufferData(buffers_wt[c], AL_FORMAT_STEREO_FLOAT32, wt_buf, WTBUFLEN * 2 * sizeof(float), WT_FREQ); alBufferData(buffers_cd[c], AL_FORMAT_STEREO_FLOAT32, cd_buf, CD_BUFLEN * 2 * sizeof(float), CD_FREQ); alBufferData(buffers_fdd[c], AL_FORMAT_STEREO_FLOAT32, fdd_buf, BUFLEN * 2 * sizeof(float), FREQ); + alBufferData(buffers_hdd[c], AL_FORMAT_STEREO_FLOAT32, hdd_buf, BUFLEN * 2 * sizeof(float), FREQ); if (init_midi) alBufferData(buffers_midi[c], AL_FORMAT_STEREO_FLOAT32, midi_buf, midi_buf_size * (int) sizeof(float), midi_freq); } else { @@ -252,6 +268,7 @@ inital(void) alBufferData(buffers_wt[c], AL_FORMAT_STEREO16, wt_buf_int16, WTBUFLEN * 2 * sizeof(int16_t), WT_FREQ); alBufferData(buffers_cd[c], AL_FORMAT_STEREO16, cd_buf_int16, CD_BUFLEN * 2 * sizeof(int16_t), CD_FREQ); alBufferData(buffers_fdd[c], AL_FORMAT_STEREO16, fdd_buf_int16, BUFLEN * 2 * sizeof(int16_t), FREQ); + alBufferData(buffers_hdd[c], AL_FORMAT_STEREO16, hdd_buf_int16, BUFLEN * 2 * sizeof(int16_t), FREQ); if (init_midi) alBufferData(buffers_midi[c], AL_FORMAT_STEREO16, midi_buf_int16, midi_buf_size * (int) sizeof(int16_t), midi_freq); } @@ -262,6 +279,7 @@ inital(void) alSourceQueueBuffers(source[I_WT], 4, buffers_wt); alSourceQueueBuffers(source[I_CD], 4, buffers_cd); alSourceQueueBuffers(source[I_FDD], 4, buffers_fdd); + alSourceQueueBuffers(source[I_HDD], 4, buffers_hdd); if (init_midi) alSourceQueueBuffers(source[I_MIDI], 4, buffers_midi); alSourcePlay(source[I_NORMAL]); @@ -269,6 +287,7 @@ inital(void) alSourcePlay(source[I_WT]); alSourcePlay(source[I_CD]); alSourcePlay(source[I_FDD]); + alSourcePlay(source[I_HDD]); if (init_midi) alSourcePlay(source[I_MIDI]); @@ -280,6 +299,7 @@ inital(void) free(music_buf); free(buf); free(fdd_buf); + free(hdd_buf); } else { if (init_midi) free(midi_buf_int16); @@ -288,11 +308,13 @@ inital(void) free(music_buf_int16); free(buf_int16); free(fdd_buf_int16); + free(hdd_buf_int16); } initialized = 1; } +extern bool fast_forward; void givealbuffer_common(const void *buf, const uint8_t src, const int size, const int freq) { @@ -300,7 +322,7 @@ givealbuffer_common(const void *buf, const uint8_t src, const int size, const in int state; ALuint buffer; - if (!initialized) + if (!initialized || fast_forward) return; alGetSourcei(source[src], AL_SOURCE_STATE, &state); @@ -311,7 +333,7 @@ givealbuffer_common(const void *buf, const uint8_t src, const int size, const in alGetSourcei(source[src], AL_BUFFERS_PROCESSED, &processed); if (processed >= 1) { - const double gain = sound_muted ? 0.0 : pow(10.0, (double) sound_gain / 20.0); + const double gain = (sound_muted) ? 0.0 : pow(10.0, (double) sound_gain / 20.0); alListenerf(AL_GAIN, (float) gain); alSourceUnqueueBuffers(source[src], 1, &buffer); @@ -328,35 +350,41 @@ givealbuffer_common(const void *buf, const uint8_t src, const int size, const in void givealbuffer(const void *buf) { - givealbuffer_common(buf, 0, BUFLEN << 1, FREQ); + givealbuffer_common(buf, I_NORMAL, BUFLEN << 1, FREQ); } void givealbuffer_music(const void *buf) { - givealbuffer_common(buf, 1, MUSICBUFLEN << 1, MUSIC_FREQ); + givealbuffer_common(buf, I_MUSIC, MUSICBUFLEN << 1, MUSIC_FREQ); } void givealbuffer_wt(const void *buf) { - givealbuffer_common(buf, 2, WTBUFLEN << 1, WT_FREQ); + givealbuffer_common(buf, I_WT, WTBUFLEN << 1, WT_FREQ); } void givealbuffer_cd(const void *buf) { - givealbuffer_common(buf, 3, CD_BUFLEN << 1, CD_FREQ); + givealbuffer_common(buf, I_CD, CD_BUFLEN << 1, CD_FREQ); } void givealbuffer_midi(const void *buf, const uint32_t size) { - givealbuffer_common(buf, 5, (int) size, midi_freq); + givealbuffer_common(buf, I_MIDI, (int) size, midi_freq); } void givealbuffer_fdd(const void *buf, const uint32_t size) { - givealbuffer_common(buf, 4, (int) size, FREQ); + givealbuffer_common(buf, I_FDD, (int) size, FREQ); +} + +void +givealbuffer_hdd(const void *buf, const uint32_t size) +{ + givealbuffer_common(buf, I_HDD, (int) size, FREQ); } \ No newline at end of file diff --git a/src/sound/snd_ac97_codec.c b/src/sound/snd_ac97_codec.c index 0713568732d..c028e429dd9 100644 --- a/src/sound/snd_ac97_codec.c +++ b/src/sound/snd_ac97_codec.c @@ -35,7 +35,7 @@ static const struct { uint16_t reset_flags; uint16_t extid_flags; uint8_t pcsr_mask; /* register 26 bits [15:8] */ - uint8_t eascr_mask; /* register 2A bits [14:11] (audio) or 56 bits ... */ + uint8_t eascr_mask; /* register 2A bits [14:11] */ uint8_t modem_flags; uint16_t gpi_mask; /* modem GPIO input-capable bits */ uint16_t gpo_mask; /* modem GPIO output-capable bits */ @@ -80,6 +80,14 @@ static const struct { .pcsr_mask = 0xff, .vendor_regs = (const ac97_vendor_reg_t[]) {{0, 0x5e, 0x0000, 0x01b0}, {0, 0x60, 0x0023, 0x0001}, {0, 0x68, 0x0000, 0xdfff}, {0}} }, + { + .device = &ice1232_device, + .misc_flags = AC97_AUDIO | AC97_AUXOUT | AC97_MONOOUT | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_MS | AC97_LPBK, + .reset_flags = AC97_HPOUT | AC97_DAC_18B | AC97_ADC_18B | (27 << AC97_3D_SHIFT), + .extid_flags = AC97_VRA | AC97_AMAP, + .pcsr_mask = 0xff, + .vendor_regs = (const ac97_vendor_reg_t[]) {{0, 0x5a, 0x0021, 0x00fd}, {0}} + }, { .device = &stac9708_device, .misc_flags = AC97_AUDIO | AC97_AUXOUT | AC97_MONOOUT | AC97_PCBEEP | AC97_PHONE | AC97_VIDEO | AC97_AUXIN | AC97_MS | AC97_LPBK, @@ -890,6 +898,20 @@ const device_t cs4297a_device = { .config = NULL }; +const device_t ice1232_device = { + .name = "ICEnsemble ICE1232 / VIA VT1611A", + .internal_name = "ice1232", + .flags = DEVICE_AC97, + .local = AC97_CODEC_ICE1232, + .init = ac97_codec_init, + .close = ac97_codec_close, + .reset = ac97_codec_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + const device_t stac9708_device = { .name = "SigmaTel STAC9708", .internal_name = "stac9708", diff --git a/src/sound/snd_ad1816.c b/src/sound/snd_ad1816.c new file mode 100644 index 00000000000..4e929794d91 --- /dev/null +++ b/src/sound/snd_ad1816.c @@ -0,0 +1,999 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Analog Devices AD1816 SoundPort audio controller emulation. + * + * Many similarities to the AD1848/CS423x WSS codec family but + * heavily modified and not register-compatible + * + * Authors: Sarah Walker, + * TheCollector1995, + * RichardG, + * win2kgamer + * + * Copyright 2008-2020 Sarah Walker. + * Copyright 2018-2020 TheCollector1995. + * Copyright 2021-2025 RichardG. + * Copyright 2025 win2kgamer + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H + +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/io.h> +#include <86box/midi.h> +#include <86box/timer.h> +#include <86box/pic.h> +#include <86box/dma.h> +#include <86box/sound.h> +#include <86box/gameport.h> +#include <86box/snd_sb.h> +#include <86box/mem.h> +#include <86box/rom.h> +#include <86box/plat_unused.h> +#include <86box/isapnp.h> +#include <86box/log.h> + +#define PNP_ROM_AD1816 "roms/sound/ad1816/ad1816.bin" + +#ifdef ENABLE_AD1816_LOG +int ad1816_do_log = ENABLE_AD1816_LOG; + +static void +ad1816_log(void *priv, const char *fmt, ...) +{ + if (ad1816_do_log) { + va_list ap; + va_start(ap, fmt); + log_out(priv, fmt, ap); + va_end(ap); + } +} +#else +# define ad1816_log(fmt, ...) +#endif + +static double ad1816_vols_5bits[32]; +static double ad1816_vols_5bits_aux_gain[32]; +static int ad1816_vols_6bits[64]; + +typedef struct ad1816_t { + uint8_t index; + uint8_t regs[16]; + uint16_t iregs[64]; + + uint16_t cur_ad1816_addr; + uint16_t cur_sb_addr; + uint16_t cur_opl_addr; + uint16_t cur_mpu_addr; + uint16_t cur_js_addr; + uint8_t cur_irq; + uint8_t cur_mpu_irq; + uint8_t cur_dma; + + int freq; + + pc_timer_t timer_count; + uint64_t timer_latch; + + pc_timer_t ad1816_irq_timer; + + uint8_t status; + int count; + int16_t out_l; + int16_t out_r; + uint8_t fmt_mask; + uint8_t dma_ff; + uint32_t dma_data; + int16_t buffer[SOUNDBUFLEN * 2]; + int pos; + uint8_t playback_pos : 2; + uint8_t enable; + uint8_t codec_enable; + + double master_l; + double master_r; + double cd_vol_l; + double cd_vol_r; + int fm_vol_l; + int fm_vol_r; + + void *gameport; + mpu_t *mpu; + sb_t *sb; + + void *pnp_card; + uint8_t pnp_rom[512]; + isapnp_device_config_t *ad1816_pnp_config; + + void * log; /* New logging system */ +} ad1816_t; + +static void +ad1816_update_mastervol(void *priv) +{ + ad1816_t *ad1816 = (ad1816_t *) priv; + + if (ad1816->iregs[14] & 0x8000) + ad1816->master_l = 0; + else + ad1816->master_l = ad1816_vols_5bits[((ad1816->iregs[14] >> 8) & 0x1f) >> 1] / 65536.0; + + if (ad1816->iregs[14] & 0x0080) + ad1816->master_r = 0; + else + ad1816->master_r = ad1816_vols_5bits[((ad1816->iregs[14]) & 0x1f) >> 1] / 65536.0; +} + +void +ad1816_filter_cd_audio(int channel, double *buffer, void *priv) +{ + ad1816_t *ad1816 = (ad1816_t *) priv; + + ad1816_update_mastervol(ad1816); + + const double cd_vol = channel ? ad1816->cd_vol_r : ad1816->cd_vol_l; + double master = channel ? ad1816->master_r : ad1816->master_l; + double c = ((*buffer * cd_vol / 1.0) * master) / 65536.0; + + *buffer = c; +} + +static void +ad1816_filter_opl(void *priv, double *out_l, double *out_r) +{ + ad1816_t *ad1816 = (ad1816_t *) priv; + + ad1816_update_mastervol(ad1816); + *out_l *= ad1816->fm_vol_l; + *out_r *= ad1816->fm_vol_r; + *out_l *= ad1816->master_l; + *out_r *= ad1816->master_r; + +} + +void +ad1816_update(ad1816_t *ad1816) +{ + for (; ad1816->pos < sound_pos_global; ad1816->pos++) { + ad1816->buffer[ad1816->pos * 2] = ad1816->out_l; + ad1816->buffer[ad1816->pos * 2 + 1] = ad1816->out_r; + } +} + +static int16_t +ad1816_process_mulaw(uint8_t byte) +{ + byte = ~byte; + int temp = (((byte & 0x0f) << 3) + 0x84); + temp <<= ((byte & 0x70) >> 4); + temp = (byte & 0x80) ? (0x84 - temp) : (temp - 0x84); + if (temp > 32767) + return 32767; + else if (temp < -32768) + return -32768; + return (int16_t) temp; +} + +static int16_t +ad1816_process_alaw(uint8_t byte) +{ + byte ^= 0x55; + int dec = ((byte & 0x0f) << 4);; + const int seg = (int) ((byte & 0x70) >> 4); + switch (seg) { + default: + dec |= 0x108; + dec <<= seg - 1; + break; + + case 0: + dec |= 0x8; + break; + + case 1: + dec |= 0x108; + break; + } + return (int16_t) ((byte & 0x80) ? dec : -dec); +} + +static uint32_t +ad1816_dma_channel_read(ad1816_t *ad1816, int channel) +{ + uint32_t ret; + + if (channel >= 4) { + if (ad1816->dma_ff) { + ret = (ad1816->dma_data & 0xff00) >> 8; + ret |= (ad1816->dma_data & 0xffff0000); + } else { + ad1816->dma_data = dma_channel_read(channel); + + if (ad1816->dma_data == DMA_NODATA) + return DMA_NODATA; + + ret = ad1816->dma_data & 0xff; + } + + ad1816->dma_ff = !ad1816->dma_ff; + } else + ret = dma_channel_read(channel); + + return ret; +} + +static void +ad1816_poll(void *priv) +{ + ad1816_t *ad1816 = (ad1816_t *) priv; + + if (ad1816->timer_latch) + timer_advance_u64(&ad1816->timer_count, ad1816->timer_latch); + else + timer_advance_u64(&ad1816->timer_count, TIMER_USEC * 1000); + + ad1816_update(ad1816); + + if (ad1816->enable) { + int32_t temp; + uint8_t format; + + format = (ad1816->regs[8] << 2) & 0xf0; + ad1816_log(ad1816->log, "AD1816 format = %04X\n", format); + ad1816_log(ad1816->log, "count = %04X, pos = %02X\n", ad1816->count, ad1816->playback_pos); + + switch (format) { + case 0x00: /* Mono, 8-bit PCM */ + ad1816->out_l = ad1816->out_r = (int16_t) ((ad1816_dma_channel_read(ad1816, ad1816->cur_dma) ^ 0x80) << 8); + ad1816->playback_pos++; + break; + + case 0x10: /* Stereo, 8-bit PCM */ + ad1816->out_l = (int16_t) ((ad1816_dma_channel_read(ad1816, ad1816->cur_dma) ^ 0x80) << 8); + ad1816->out_r = (int16_t) ((ad1816_dma_channel_read(ad1816, ad1816->cur_dma) ^ 0x80) << 8); + ad1816->playback_pos += 2; + break; + + case 0x20: /* Mono, 8-bit Mu-Law */ + ad1816->out_l = ad1816->out_r = ad1816_process_mulaw(ad1816_dma_channel_read(ad1816, ad1816->cur_dma)); + ad1816->playback_pos++; + break; + + case 0x30: /* Stereo, 8-bit Mu-Law */ + ad1816->out_l = ad1816_process_mulaw(ad1816_dma_channel_read(ad1816, ad1816->cur_dma)); + ad1816->out_r = ad1816_process_mulaw(ad1816_dma_channel_read(ad1816, ad1816->cur_dma)); + ad1816->playback_pos += 2; + break; + + case 0x40: /* Mono, 16-bit PCM little endian */ + temp = (int32_t) ad1816_dma_channel_read(ad1816, ad1816->cur_dma); + ad1816->out_l = ad1816->out_r = (int16_t) ((ad1816_dma_channel_read(ad1816, ad1816->cur_dma) << 8) | temp); + ad1816->playback_pos += 2; + break; + + case 0x50: /* Stereo, 16-bit PCM little endian */ + temp = (int32_t) ad1816_dma_channel_read(ad1816, ad1816->cur_dma); + ad1816->out_l = (int16_t) ((ad1816_dma_channel_read(ad1816, ad1816->cur_dma) << 8) | temp); + temp = (int32_t) ad1816_dma_channel_read(ad1816, ad1816->cur_dma); + ad1816->out_r = (int16_t) ((ad1816_dma_channel_read(ad1816, ad1816->cur_dma) << 8) | temp); + ad1816->playback_pos += 4; + break; + + case 0x60: /* Mono, 8-bit A-Law */ + ad1816->out_l = ad1816->out_r = ad1816_process_alaw(ad1816_dma_channel_read(ad1816, ad1816->cur_dma)); + ad1816->playback_pos++; + break; + + case 0x70: /* Stereo, 8-bit A-Law */ + ad1816->out_l = ad1816_process_alaw(ad1816_dma_channel_read(ad1816, ad1816->cur_dma)); + ad1816->out_r = ad1816_process_alaw(ad1816_dma_channel_read(ad1816, ad1816->cur_dma)); + ad1816->playback_pos += 2; + break; + + /* 0x80, 0x90, 0xa0, 0xb0 reserved */ + + case 0xc0: /* Mono, 16-bit PCM big endian */ + temp = (int32_t) ad1816_dma_channel_read(ad1816, ad1816->cur_dma); + ad1816->out_l = ad1816->out_r = (int16_t) (ad1816_dma_channel_read(ad1816, ad1816->cur_dma) | (temp << 8)); + ad1816->playback_pos += 2; + break; + + case 0xd0: /* Stereo, 16-bit PCM big endian */ + temp = (int32_t) ad1816_dma_channel_read(ad1816, ad1816->cur_dma); + ad1816->out_l = (int16_t) (ad1816_dma_channel_read(ad1816, ad1816->cur_dma) | (temp << 8)); + temp = (int32_t) ad1816_dma_channel_read(ad1816, ad1816->cur_dma); + ad1816->out_r = (int16_t) (ad1816_dma_channel_read(ad1816, ad1816->cur_dma) | (temp << 8)); + ad1816->playback_pos += 4; + break; + + /* 0xe0 and 0xf0 reserved */ + + default: + break; + } + if (ad1816->iregs[4] & 0x8000) + ad1816->out_l = 0; + else + ad1816->out_l = (int16_t) ((ad1816->out_l * ad1816_vols_6bits[((ad1816->iregs[4] >> 8) & 0x3f) >> 1]) >> 16); + + if (ad1816->iregs[4] & 0x0080) + ad1816->out_r = 0; + else + ad1816->out_r = (int16_t) ((ad1816->out_r * ad1816_vols_6bits[(ad1816->iregs[4] & 0x3f) >> 1]) >> 16); + + if (ad1816->count < 0) { + ad1816->count = ad1816->iregs[8]; + ad1816->regs[1] |= 0x80; + if (ad1816->iregs[1] & 0x8000) { + ad1816_log(ad1816->log, "AD1816 Playback interrupt fired\n"); + picint(1 << ad1816->cur_irq); + } + else { + ad1816_log(ad1816->log, "AD1816 Playback interrupt cleared\n"); + picintc(1 << ad1816->cur_irq); + } + } + /* AD1816 count decrements every 4 bytes */ + if (!(ad1816->playback_pos & 3)) + ad1816->count--; + } else { + ad1816->out_l = ad1816->out_r = 0; + } +} + +static void +ad1816_get_buffer(int32_t *buffer, int len, void *priv) +{ + ad1816_t *ad1816 = (ad1816_t *) priv; + + /* Don't play audio if the DAC mute or chip powerdown bits are set */ + if ((ad1816->iregs[44] & 0x8000) || (ad1816->iregs[44] & 0x0008)) + return; + + ad1816_update_mastervol(ad1816); + ad1816_update(ad1816); + for (int c = 0; c < len * 2; c++) { + double out_l = 0.0; + double out_r = 0.0; + + out_l = (ad1816->buffer[c] * ad1816->master_l); + out_r = (ad1816->buffer[c + 1] * ad1816->master_r); + + buffer[c] += (int32_t) out_l; + buffer[c + 1] += (int32_t) out_r; + } + + ad1816->pos = 0; + + /* sbprov2 part */ + sb_get_buffer_sbpro(buffer, len, ad1816->sb); +} + +static void +ad1816_updatefreq(ad1816_t *ad1816) +{ + double freq; + + if (ad1816->iregs[2] > 55200) + ad1816->iregs[2] = 55200; + freq = ad1816->iregs[2]; + + ad1816->freq = (int) trunc(freq); + ad1816->timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / (double) ad1816->freq)); + + ad1816_log(ad1816->log, "AD1816: Frequency set to %f\n", freq); +} + +static void +ad1816_reg_write(uint16_t addr, uint8_t val, void *priv) +{ + ad1816_t *ad1816 = (ad1816_t *) priv; + uint16_t iridx = ad1816->index; + uint8_t port = addr - ad1816->cur_ad1816_addr; + double timebase = 0; + + switch (port) { + case 0: /* Status/Indirect address */ + ad1816->regs[0] = val | 0x80; + ad1816->index = val & 0x3f; + break; + case 1: /* Interrupt Status */ + ad1816->regs[1] = 0x00; /* Sticky read/clear */ + break; + case 2: /* Indirect data low byte */ + ad1816->regs[2] = val; + ad1816->iregs[0] = val; /* Indirect low byte temp */ + break; + case 3: /* Indirect data high byte */ + ad1816->regs[3] = val; + switch (iridx) { + case 1: /* Interrupt Enable/External Control */ + ad1816->iregs[1] = ((val << 8) | ad1816->regs[2]); + if (ad1816->iregs[1] & 0x0080) { + ad1816_log(ad1816->log, "Timer Enable\n"); + timebase = (ad1816->iregs[44] & 0x0100) ? 100000 : 10; + timer_set_delay_u64(&ad1816->ad1816_irq_timer, (ad1816->iregs[13] * timebase * TIMER_USEC)); + } + else { + ad1816_log(ad1816->log, "Timer Disable\n"); + timer_disable(&ad1816->ad1816_irq_timer); + } + break; + case 2: /* Voice Playback Sample Rate */ + ad1816->iregs[2] = ((val << 8) | ad1816->regs[2]); + ad1816_updatefreq(ad1816); + break; + case 3: /* Voice Capture Sample Rate */ + ad1816->iregs[3] = ((val << 8) | ad1816->regs[2]); + break; + case 4: /* Voice Attenuation */ + ad1816->iregs[4] = ((val << 8) | ad1816->regs[2]); + break; + case 5: /* FM Attenuation */ + ad1816->iregs[5] = ((val << 8) | ad1816->regs[2]); + /* FM has distortion problems at the highest volume setting and the Win95 driver only uses the upper + 16 values, currently needs a small hack to use lower volumes if the FM mixer is set too high */ + if (ad1816->iregs[5] & 0x8000) + ad1816->fm_vol_l = 0; + else { + if (((ad1816->iregs[5] >> 8) & 0x3F) <= 0x0F) + ad1816->fm_vol_l = ad1816_vols_6bits[((ad1816->iregs[5] >> 8) & 0x3f) + 0x10]; + else + ad1816->fm_vol_l = ad1816_vols_6bits[((ad1816->iregs[5] >> 8) & 0x3f)]; + } + if (ad1816->iregs[5] & 0x0080) + ad1816->fm_vol_r = 0; + else { + if ((ad1816->iregs[5] & 0x3F) <= 0x0F) + ad1816->fm_vol_r = ad1816_vols_6bits[(ad1816->iregs[5] & 0x3f) + 0x10]; + else + ad1816->fm_vol_r = ad1816_vols_6bits[(ad1816->iregs[5] & 0x3f)]; + } + break; + case 6: /* I2S(1) Attenuation */ + ad1816->iregs[6] = ((val << 8) | ad1816->regs[2]); + break; + case 7: /* I2S(0) Attenuation */ + ad1816->iregs[7] = ((val << 8) | ad1816->regs[2]); + break; + case 8: /* Playback Base Count */ + ad1816->iregs[8] = ((val << 8) | ad1816->regs[2]); + ad1816->iregs[9] = ((val << 8) | ad1816->regs[2]); + ad1816->count = ad1816->iregs[8]; + break; + case 9: /* Playback Current Count */ + ad1816->iregs[9] = ((val << 8) | ad1816->regs[2]); + break; + case 10: /* Capture Base Count */ + ad1816->iregs[10] = ((val << 8) | ad1816->regs[2]); + ad1816->iregs[11] = ((val << 8) | ad1816->regs[2]); + break; + case 11: /* Capture Current Count */ + ad1816->iregs[11] = ((val << 8) | ad1816->regs[2]); + break; + case 12: /* Timer Base Count */ + ad1816->iregs[12] = ((val << 8) | ad1816->regs[2]); + ad1816->iregs[13] = ((val << 8) | ad1816->regs[2]); + break; + case 13: /* Timer Current Count */ + ad1816->iregs[13] = ((val << 8) | ad1816->regs[2]); + break; + case 14: /* Master Volume Attenuation */ + ad1816->iregs[14] = ((val << 8) | ad1816->regs[2]); + break; + case 15: /* CD Gain/Attenuation */ + ad1816->iregs[15] = ((val << 8) | ad1816->regs[2]); + if (ad1816->iregs[15] & 0x8000) + ad1816->cd_vol_l = 0; + else + ad1816->cd_vol_l = ad1816_vols_5bits_aux_gain[(ad1816->iregs[15] >> 8) & 0x1f]; + if (ad1816->iregs[15] & 0x0080) + ad1816->cd_vol_r = 0; + else + ad1816->cd_vol_r = ad1816_vols_5bits_aux_gain[ad1816->iregs[15] & 0x1f]; + break; + case 16: /* Synth Gain/Attenuation */ + ad1816->iregs[16] = ((val << 8) | ad1816->regs[2]); + break; + case 17: /* Vid Gain/Attenuation */ + ad1816->iregs[17] = ((val << 8) | ad1816->regs[2]); + break; + case 18: /* Line Gain/Attenuation */ + ad1816->iregs[18] = ((val << 8) | ad1816->regs[2]); + break; + case 19: /* Mic/Phone_In Gain/Attenuation */ + ad1816->iregs[19] = ((val << 8) | ad1816->regs[2]); + break; + case 20: /* ADC Source Select/ADC PGA */ + ad1816->iregs[20] = ((val << 8) | ad1816->regs[2]); + break; + case 32: /* Chip Configuration */ + ad1816->iregs[32] = ((val << 8) | ad1816->regs[2]); + if (ad1816->iregs[32] & 0x8000) { + ad1816->codec_enable = 1; + sound_set_cd_audio_filter(NULL, NULL); /* Seems to be necessary for the filter below to apply */ + sound_set_cd_audio_filter(ad1816_filter_cd_audio, ad1816); + ad1816->sb->opl_mixer = ad1816; + ad1816->sb->opl_mix = ad1816_filter_opl; + } + else { + ad1816->codec_enable = 0; + sound_set_cd_audio_filter(NULL, NULL); /* Seems to be necessary for the filter below to apply */ + sound_set_cd_audio_filter(sbpro_filter_cd_audio, ad1816->sb); /* Use SBPro to filter when codec is disabled */ + ad1816->sb->opl_mixer = NULL; + ad1816->sb->opl_mix = NULL; + } + break; + case 33: /* DSP Configuration */ + ad1816->iregs[33] = ((val << 8) | ad1816->regs[2]); + if ((ad1816->iregs[1] & 0x0800) && (ad1816->iregs[33] & 0x2000)) { + ad1816_log(ad1816->log, "Firing DSP interrupt\n"); + ad1816->regs[1] |= 0x08; + picint(1 << ad1816->cur_irq); + } + break; + case 34: /* FM Sample Rate */ + ad1816->iregs[34] = ((val << 8) | ad1816->regs[2]); + break; + case 35: /* I2S(1) Sample Rate */ + ad1816->iregs[35] = ((val << 8) | ad1816->regs[2]); + break; + case 36: /* I2S(0) Sample Rate */ + ad1816->iregs[36] = ((val << 8) | ad1816->regs[2]); + break; + case 37: /* Reserved on AD1816, Modem sample rate on AD1815 */ + break; + case 38: /* Programmable Clock Rate */ + ad1816->iregs[38] = ((val << 8) | ad1816->regs[2]); + break; + case 39: /* 3D Phat Stereo Control/Phone_Out Attenuation on AD1816, Modem DAC/ADC attenuation on AD1815 */ + ad1816->iregs[39] = ((val << 8) | ad1816->regs[2]); + break; + case 40: /* Reserved on AD1816, Modem mix attenuation on AD1815 */ + break; + case 41: /* Hardware Volume Button Modifier */ + ad1816->iregs[41] = ((val << 8) | ad1816->regs[2]); + break; + case 42: /* DSP Mailbox 0 */ + ad1816->iregs[42] = ((val << 8) | ad1816->regs[2]); + break; + case 43: /* DSP Mailbox 1 */ + ad1816->iregs[43] = ((val << 8) | ad1816->regs[2]); + break; + case 44: /* Powerdown and Timer Control */ + ad1816->iregs[44] = ((val << 8) | ad1816->regs[2]); + break; + case 45: /* Version/ID */ + break; + case 46: /* Reserved test register */ + break; + default: + break; + } + ad1816_log(ad1816->log, "AD1816 Indirect Register write: idx = %02X, val = %04X\n", ad1816->index, ad1816->iregs[iridx]); + break; + case 4: /* PIO Debug */ + ad1816->regs[4] = 0x00; /* Sticky read/clear */ + break; + case 5: /* PIO Status (RO) */ + break; + case 6: /* PIO Data */ + ad1816->regs[6] = val; + break; + case 7: /* Reserved */ + break; + case 8: /* Playback Config */ + ad1816->regs[8] = val; + if (!ad1816->enable && val & 0x01) { + ad1816->playback_pos = 0; + ad1816->dma_ff = 0; + if (ad1816->timer_latch) + timer_set_delay_u64(&ad1816->timer_count, ad1816->timer_latch); + else + timer_set_delay_u64(&ad1816->timer_count, TIMER_USEC); + } + ad1816->enable = (val & 0x01); + if (!ad1816->enable) { + timer_disable(&ad1816->timer_count); + ad1816->out_l = ad1816->out_r = 0; + } + break; + case 9: /* Capture Config */ + ad1816->regs[9] = val; + break; + case 10: /* Reserved on AD1816, PIO modem out/in bits 7-0 on AD1815 */ + break; + case 11: /* Reserved on AD1816, PIO modem out/in bits 15-8 on AD1815 */ + break; + case 12: /* Joystick Raw Data (RO) */ + break; + case 13: /* Joystick Control */ + ad1816->regs[13] = ((val & 0x7f) | (ad1816->regs[13] & 0x80)); + break; + case 14: /* Joystick Position Low Byte (RO) */ + case 15: /* Joystick Position Low Byte (RO) */ + break; + } + ad1816_log(ad1816->log, "AD1816 Write: idx = %02X, val = %02X\n", port, val); +} + +static uint8_t +ad1816_reg_read(uint16_t addr, void *priv) +{ + ad1816_t *ad1816 = (ad1816_t *) priv; + uint16_t iridx = ad1816->index; + uint8_t temp = 0xFF; + uint8_t port = addr - ad1816->cur_ad1816_addr; + + switch (port) { + case 0: + temp = ad1816->regs[port]; + break; + case 1: + temp = ad1816->regs[port]; + temp |= ((ad1816->sb->dsp.sb_irq8) ? 1 : 0); + break; + case 2: + temp = (ad1816->iregs[iridx] & 0x00ff); + break; + case 3: + temp = (ad1816->iregs[iridx] & 0xff00) >> 8; + break; + case 4 ... 15: + temp = ad1816->regs[port]; + break; + default: + break; + } + + ad1816_log(ad1816->log, "AD1816 Read: idx = %02X, val = %02X\n", port, temp); + return temp; +} + +static void +ad1816_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *priv) +{ + ad1816_t *ad1816 = (ad1816_t *) priv; + + ad1816_log(ad1816->log, "PnP Config changed\n"); + + switch(ld) { + case 0: /* Audio */ + if (ad1816->cur_ad1816_addr) { + io_removehandler(ad1816->cur_ad1816_addr, 0x10, ad1816_reg_read, NULL, NULL, ad1816_reg_write, NULL, NULL, ad1816); + ad1816->cur_ad1816_addr = 0; + } + + if (ad1816->cur_opl_addr) { + io_removehandler(ad1816->cur_opl_addr, 0x0004, ad1816->sb->opl.read, NULL, NULL, ad1816->sb->opl.write, NULL, NULL, ad1816->sb->opl.priv); + ad1816->cur_opl_addr = 0; + } + + if (ad1816->cur_sb_addr) { + sb_dsp_setaddr(&ad1816->sb->dsp, 0); + io_removehandler(ad1816->cur_sb_addr + 4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, ad1816->sb); + io_removehandler(ad1816->cur_sb_addr + 0, 0x0004, ad1816->sb->opl.read, NULL, NULL, ad1816->sb->opl.write, NULL, NULL, ad1816->sb->opl.priv); + io_removehandler(ad1816->cur_sb_addr + 8, 0x0002, ad1816->sb->opl.read, NULL, NULL, ad1816->sb->opl.write, NULL, NULL, ad1816->sb->opl.priv); + ad1816->cur_sb_addr = 0; + } + + sb_dsp_setirq(&ad1816->sb->dsp, 0); + sb_dsp_setdma8(&ad1816->sb->dsp, 0); + + if (config->activate) { + if (config->io[0].base != ISAPNP_IO_DISABLED) { + ad1816->cur_sb_addr = config->io[0].base; + ad1816_log(ad1816->log, "Updating SB DSP I/O port, SB DSP addr = %04X\n", ad1816->cur_sb_addr); + sb_dsp_setaddr(&ad1816->sb->dsp, ad1816->cur_sb_addr); + io_sethandler(ad1816->cur_sb_addr + 4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, ad1816->sb); + io_sethandler(ad1816->cur_sb_addr + 0, 0x0004, ad1816->sb->opl.read, NULL, NULL, ad1816->sb->opl.write, NULL, NULL, ad1816->sb->opl.priv); + io_sethandler(ad1816->cur_sb_addr + 8, 0x0002, ad1816->sb->opl.read, NULL, NULL, ad1816->sb->opl.write, NULL, NULL, ad1816->sb->opl.priv); + } + if (config->io[1].base != ISAPNP_IO_DISABLED) { + ad1816->cur_opl_addr = config->io[1].base; + ad1816_log(ad1816->log, "Updating OPL I/O port, OPL addr = %04X\n", ad1816->cur_opl_addr); + io_sethandler(ad1816->cur_opl_addr, 0x0004, ad1816->sb->opl.read, NULL, NULL, ad1816->sb->opl.write, NULL, NULL, ad1816->sb->opl.priv); + + } + if (config->io[2].base != ISAPNP_IO_DISABLED) { + ad1816->cur_ad1816_addr = config->io[2].base; + ad1816_log(ad1816->log, "Updating AD1816 I/O port, AD1816 addr = %04X\n", ad1816->cur_ad1816_addr); + io_sethandler(ad1816->cur_ad1816_addr, 0x10, ad1816_reg_read, NULL, NULL, ad1816_reg_write, NULL, NULL, ad1816); + } + if (config->irq[0].irq != ISAPNP_IRQ_DISABLED) { + ad1816->cur_irq = config->irq[0].irq; + sb_dsp_setirq(&ad1816->sb->dsp, ad1816->cur_irq); + ad1816_log(ad1816->log, "Updated AD1816/SB IRQ to %02X\n", ad1816->cur_irq); + } + if (config->dma[0].dma != ISAPNP_DMA_DISABLED) { + ad1816->cur_dma = config->dma[0].dma; + sb_dsp_setdma8(&ad1816->sb->dsp, ad1816->cur_dma); + ad1816_log(ad1816->log, "Updated AD1816/SB DMA to %02X\n", ad1816->cur_dma); + } + } + break; + case 1: /* MPU401 */ + if (config->activate) { + if (config->io[0].base != ISAPNP_IO_DISABLED) { + ad1816->cur_mpu_addr = config->io[0].base; + ad1816_log(ad1816->log, "Updating MPU401 I/O port, MPU401 addr = %04X\n", ad1816->cur_mpu_addr); + mpu401_change_addr(ad1816->mpu, ad1816->cur_mpu_addr); + } + if (config->irq[0].irq != ISAPNP_IRQ_DISABLED) { + ad1816->cur_mpu_irq = config->irq[0].irq; + mpu401_setirq(ad1816->mpu, ad1816->cur_mpu_irq); + ad1816_log(ad1816->log, "Updated MPU401 IRQ to %02X\n", ad1816->cur_mpu_irq); + } + } + break; + case 2: /* Gameport */ + ad1816->cur_js_addr = config->io[0].base; + gameport_remap(ad1816->gameport, (config->activate && (config->io[0].base != ISAPNP_IO_DISABLED)) ? config->io[0].base : 0); + break; + default: + break; + } +} + +void +ad1816_irq_poll(void *priv) +{ + ad1816_t *ad1816 = (ad1816_t *) priv; + if (ad1816->iregs[1] & 0x2000) { + ad1816_log(ad1816->log, "Firing timer IRQ\n"); + picint(1 << ad1816->cur_irq); + ad1816_log(ad1816->log, "Setting TI bit\n"); + ad1816->regs[1] = ad1816->regs[1] | 0x20; + ad1816_log(ad1816->log, "Reloading Timer Count\n"); + ad1816->iregs[13] = ad1816->iregs[12]; + } +} + +static void * +ad1816_init(const device_t *info) +{ + ad1816_t *ad1816 = calloc(1, sizeof(ad1816_t)); + uint8_t c; + double attenuation; + + ad1816->cur_ad1816_addr = 0x530; + ad1816->cur_sb_addr = 0x220; + ad1816->cur_opl_addr = 0x388; + ad1816->cur_mpu_addr = 0x330; + ad1816->cur_js_addr = 0x200; + ad1816->cur_irq = 5; + ad1816->cur_mpu_irq = 9; + ad1816->cur_dma = 1; + ad1816->enable = 1; + + ad1816->regs[0] = 0x80; + ad1816->regs[13] = 0xf0; + ad1816->regs[14] = 0xff; + ad1816->regs[15] = 0xff; + + ad1816->iregs[01] = 0x0102; + ad1816->iregs[02] = 0x1f40; + ad1816->iregs[03] = 0x1f40; + ad1816->iregs[04] = 0x8080; + ad1816->iregs[05] = 0x8080; + ad1816->iregs[06] = 0x8080; + ad1816->iregs[07] = 0x8080; + ad1816->iregs[15] = 0x8888; + ad1816->iregs[16] = 0x8888; + ad1816->iregs[17] = 0x8888; + ad1816->iregs[18] = 0x8888; + ad1816->iregs[19] = 0x8888; + ad1816->iregs[32] = 0x00f0; + ad1816->iregs[34] = 0x5622; + ad1816->iregs[35] = 0xac44; + ad1816->iregs[36] = 0xac44; + ad1816->iregs[38] = 0xac44; + ad1816->iregs[39] = 0x8000; + ad1816->iregs[41] = 0x001b; + ad1816->iregs[45] = 0x0000; /* Version/ID */ + + ad1816->log = log_open("AD1816"); + + ad1816->gameport = gameport_add(&gameport_pnp_device); + gameport_remap(ad1816->gameport, ad1816->cur_js_addr); + + /* Set up Sound System direct registers */ + io_sethandler(ad1816->cur_ad1816_addr, 0x10, ad1816_reg_read, NULL,NULL, ad1816_reg_write, NULL, NULL, ad1816); + + ad1816_updatefreq(ad1816); + + ad1816->sb = calloc(1, sizeof(sb_t)); + ad1816->sb->opl_enabled = 1; + + sb_dsp_set_real_opl(&ad1816->sb->dsp, FM_YMF262); + sb_dsp_init(&ad1816->sb->dsp, SBPRO2_DSP_302, SB_SUBTYPE_DEFAULT, ad1816); + sb_dsp_setaddr(&ad1816->sb->dsp, ad1816->cur_sb_addr); + sb_dsp_setirq(&ad1816->sb->dsp, ad1816->cur_irq); + sb_dsp_setirq(&ad1816->sb->dsp, ad1816->cur_dma); + sb_ct1345_mixer_reset(ad1816->sb); + + fm_driver_get(FM_YMF262, &ad1816->sb->opl); + io_sethandler(ad1816->cur_sb_addr + 0, 0x0004, ad1816->sb->opl.read, NULL, NULL, ad1816->sb->opl.write, NULL, NULL, ad1816->sb->opl.priv); + io_sethandler(ad1816->cur_sb_addr + 8, 0x0002, ad1816->sb->opl.read, NULL, NULL, ad1816->sb->opl.write, NULL, NULL, ad1816->sb->opl.priv); + io_sethandler(ad1816->cur_opl_addr, 0x0004, ad1816->sb->opl.read, NULL, NULL, ad1816->sb->opl.write, NULL, NULL, ad1816->sb->opl.priv); + + io_sethandler(ad1816->cur_sb_addr + 4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, ad1816->sb); + + sound_add_handler(ad1816_get_buffer, ad1816); + music_add_handler(sb_get_music_buffer_sbpro, ad1816->sb); + + sound_set_cd_audio_filter(NULL, NULL); /* Seems to be necessary for the filter below to apply */ + sound_set_cd_audio_filter(sbpro_filter_cd_audio, ad1816->sb); /* Default SBPro mode CD audio filter */ + + ad1816->mpu = (mpu_t *) calloc(1, sizeof(mpu_t)); + mpu401_init(ad1816->mpu, ad1816->cur_mpu_addr, ad1816->cur_mpu_irq, M_UART, device_get_config_int("receive_input401")); + + if (device_get_config_int("receive_input")) + midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &ad1816->sb->dsp); + + const char *pnp_rom_file = NULL; + uint16_t pnp_rom_len = 512; + pnp_rom_file = PNP_ROM_AD1816; + + uint8_t *pnp_rom = NULL; + if (pnp_rom_file) { + FILE *fp = rom_fopen(pnp_rom_file, "rb"); + if (fp) { + if (fread(ad1816->pnp_rom, 1, pnp_rom_len, fp) == pnp_rom_len) + pnp_rom = ad1816->pnp_rom; + fclose(fp); + } + } + ad1816->pnp_card = isapnp_add_card(pnp_rom, sizeof(ad1816->pnp_rom), ad1816_pnp_config_changed, + NULL, NULL, NULL, ad1816); + + timer_add(&ad1816->timer_count, ad1816_poll, ad1816, 0); + + timer_add(&ad1816->ad1816_irq_timer, ad1816_irq_poll, ad1816, 0); + + /* Calculate attenuation values for both the 6-bit and 5-bit volume controls */ + for (c = 0; c < 64; c++) { + attenuation = 0.0; + if (c & 0x01) + attenuation -= 1.5; + if (c & 0x02) + attenuation -= 3.0; + if (c & 0x04) + attenuation -= 6.0; + if (c & 0x08) + attenuation -= 12.0; + if (c & 0x10) + attenuation -= 24.0; + if (c & 0x20) + attenuation -= 48.0; + + attenuation = pow(10, attenuation / 10); + + ad1816_vols_6bits[c] = (int) (attenuation * 65536); + } + + for (c = 0; c < 32; c++) { + attenuation = 0.0; + if (c & 0x01) + attenuation -= 1.5; + if (c & 0x02) + attenuation -= 3.0; + if (c & 0x04) + attenuation -= 6.0; + if (c & 0x08) + attenuation -= 12.0; + if (c & 0x10) + attenuation -= 24.0; + + attenuation = pow(10, attenuation / 10); + + ad1816_vols_5bits[c] = (attenuation * 65536); + } + + for (c = 0; c < 32; c++) { + attenuation = 12.0; + if (c & 0x01) + attenuation -= 1.5; + if (c & 0x02) + attenuation -= 3.0; + if (c & 0x04) + attenuation -= 6.0; + if (c & 0x08) + attenuation -= 12.0; + if (c & 0x10) + attenuation -= 24.0; + + attenuation = pow(10, attenuation / 10); + + ad1816_vols_5bits_aux_gain[c] = (attenuation * 65536); + } + + return ad1816; +} + +static void +ad1816_close(void *priv) +{ + ad1816_t *ad1816 = (ad1816_t *) priv; + + if (ad1816->log != NULL) { + log_close(ad1816->log); + ad1816->log = NULL; + } + + sb_close(ad1816->sb); + free(ad1816->mpu); + free(priv); +} + +static int +ad1816_available(void) +{ + return rom_present(PNP_ROM_AD1816); +} + +static void +ad1816_speed_changed(void *priv) +{ + ad1816_t *ad1816 = (ad1816_t *) priv; + + ad1816->timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / (double) ad1816->freq)); + + sb_speed_changed(ad1816->sb); +} + +static const device_config_t ad1816_config[] = { + // clang-format off + { + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { + .name = "receive_input401", + .description = "Receive MIDI input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t ad1816_device = { + .name = "Analog Devices AD1816", + .internal_name = "ad1816", + .flags = DEVICE_ISA16, + .local = 0, + .init = ad1816_init, + .close = ad1816_close, + .reset = NULL, + .available = ad1816_available, + .speed_changed = ad1816_speed_changed, + .force_redraw = NULL, + .config = ad1816_config +}; + diff --git a/src/sound/snd_azt2316a.c b/src/sound/snd_azt2316a.c index 3eebf616e02..08fca0f8790 100644 --- a/src/sound/snd_azt2316a.c +++ b/src/sound/snd_azt2316a.c @@ -1,4 +1,25 @@ /* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Aztech Sound Galaxy series audio controller emulation. + * + * Authors: Cacodemon345 + * Eluan Costa Miranda + * win2kgamer + * + * Copyright 2022 Cacodemon345. + * Copyright 2020 Eluan Costa Miranda. + * Copyright 2025-2026 win2kgamer + */ + +/* + * Original header and notes: + * * TYPE 0x11: (Washington) * Aztech MMPRO16AB, * Aztech Sound Galaxy Pro 16 AB @@ -66,7 +87,7 @@ * to call the original functions, except for initialization. * * TODO/Notes: - * -Some stuff still not understood on I/O addresses 0x624 and 0x530-0x533. + * -Some stuff still not understood on I/O address 0x624. * -Is the CS42xx dither mode used anywhere? Implement. * -What are the voice commands mode in Win95 mixer again? * -Configuration options not present on Aztech's CONFIG.EXE have been commented @@ -100,14 +121,6 @@ * this behaves like a card with a regular interface disabled by jumper and * the configuration just adds/removes the drivers (which will see other IDE * interfaces present) from the boot process. - * -Continue reverse engineering to see if the AZT1605 shares the SB DMA with - * WSS or if it is set separately by the TSR loaded on boot. Currently it is - * only set by PCem config and then saved to EEPROM (which would make it fixed - * if loading from EEPROM too). - * -Related to the previous note, part of the SBPROV2 emulation on the CLINTON - * family appears to be implemented with a TSR. It's better to remove the TSR - * for now. I need to investigate this. Mixer is also weird under DOS (and - * wants to save to EEPROM? I don't think the WASHINGTON does this). * -Search for TODO in this file. :-) * * Misc things I use to test for regressions: Windows sounds, Descent under @@ -147,6 +160,7 @@ #include <86box/nvr.h> #include <86box/pic.h> #include <86box/sound.h> +#include <86box/gameport.h> #include <86box/snd_ad1848.h> #include <86box/snd_azt2316a.h> #include <86box/snd_sb.h> @@ -159,7 +173,7 @@ int aztech_do_log = ENABLE_AZTECH_LOG; static void aztech_log(void *priv, const char *fmt, ...) { - if (aztech_log) { + if (aztech_do_log) { va_list ap; va_start(ap, fmt); log_out(priv, fmt, ap); @@ -187,6 +201,8 @@ static int azt2316a_wss_irq[8] = { 5, 7, 9, 10, 11, 12, 14, 15 }; /* W95 only us static uint16_t azt2316a_wss_addr[4] = {0x530, 0x604, 0xe80, 0xf40}; #endif +static double aztpr16_vols_5bits[32]; + typedef struct azt2316a_t { int type; @@ -200,8 +216,11 @@ typedef struct azt2316a_t { int cur_wss_enabled; int cur_wss_irq; int cur_wss_dma; + int cur_wss_dma16; /* AZTPR16 16-bit DMA */ int cur_mpu401_irq; int cur_mpu401_enabled; + int gameport_enabled; + void *gameport; uint32_t config_word; uint32_t config_word_unlocked; @@ -216,6 +235,24 @@ typedef struct azt2316a_t { void * log; /* New logging system */ } azt2316a_t; +void +aztpr16_update_mixer(void *priv) +{ + azt2316a_t *azt2316a = (azt2316a_t *) priv; + + aztech_log(azt2316a->log, "Aztech AZTPR16 Mixer update\n"); + + azt2316a->ad1848.regs[2] = ((~azt2316a->sb->mixer_sbpro.regs[0xa0]) & 0x1f); /* CD L */ + azt2316a->ad1848.cd_vol_l = aztpr16_vols_5bits[azt2316a->ad1848.regs[2] & 0x1f]; + azt2316a->ad1848.regs[3] = ((~azt2316a->sb->mixer_sbpro.regs[0xa2]) & 0x1f); /* CD R */ + azt2316a->ad1848.cd_vol_r = aztpr16_vols_5bits[azt2316a->ad1848.regs[3] & 0x1f]; + azt2316a->ad1848.regs[4] = ((~azt2316a->sb->mixer_sbpro.regs[0x8c]) & 0x1f); /* FM L */ + azt2316a->ad1848.regs[5] = ((~azt2316a->sb->mixer_sbpro.regs[0x8e]) & 0x1f); /* FM R */ + azt2316a->ad1848.regs[6] = (((~azt2316a->sb->mixer_sbpro.regs[0x84]) & 0x3f) >> 1); /* Master L */ + azt2316a->ad1848.regs[7] = (((~azt2316a->sb->mixer_sbpro.regs[0x86]) & 0x3f) >> 1); /* Master R */ + +} + static void azt1605_filter_opl(void *priv, double *out_l, double *out_r) { @@ -230,9 +267,6 @@ azt2316a_wss_read(uint16_t addr, void *priv) const azt2316a_t *azt2316a = (azt2316a_t *) priv; uint8_t temp; - /* TODO: when windows is initializing, writing 0x48, 0x58 and 0x60 to - 0x530 makes reading from 0x533 return 0x44, but writing 0x50 - makes this return 0x04. Why? */ if (addr & 1) temp = 4 | (azt2316a->wss_config & 0x40); else @@ -275,35 +309,207 @@ azt2316a_wss_write(uint16_t addr, uint8_t val, void *priv) /* generate a config word based on current settings */ static void -azt1605_create_config_word(void *priv) +aztpr16_create_config_word(void *priv) { azt2316a_t *azt2316a = (azt2316a_t *) priv; uint32_t temp = 0; /* not implemented / hardcoded */ - uint8_t game_enable = 1; - uint8_t cd_type = 0; /* TODO: see if the cd-rom was originally connected there on the real machines emulated by 86Box (Packard Bell Legend 100CD, Itautec Infoway Multimidia, etc) */ - uint8_t cd_dma8 = -1; + uint8_t cd_type = 1; uint8_t cd_irq = 0; switch (azt2316a->cur_addr) { case 0x220: // do nothing -#if 0 - temp += 0 << 0; -#endif break; case 0x240: temp += 1 << 0; break; -#if 0 - case 0x260: // TODO: INVALID? + case 0x260: temp += 2 << 0; break; - case 0x280: // TODO: INVALID? + case 0x280: temp += 3 << 0; break; -#endif + default: + break; + } + + switch (azt2316a->cur_irq) { + case 2: + temp += 1 << 8; + break; + case 5: + temp += 1 << 9; + break; + case 7: + temp += 1 << 10; + break; + case 10: + temp += 1 << 11; + break; + + default: + break; + } + + switch (azt2316a->cur_wss_addr) { + case 0x530: + // do nothing + break; + case 0x604: + temp += 1 << 16; + break; + case 0xE80: + temp += 2 << 16; + break; + case 0xF40: + temp += 3 << 16; + break; + + default: + break; + } + + if (azt2316a->cur_wss_enabled) + temp += 1 << 18; + + if (azt2316a->gameport_enabled) + temp += 1 << 4; + + switch (azt2316a->cur_mpu401_addr) { + case 0x300: + // do nothing + break; + case 0x330: + temp += 1 << 2; + break; + + default: + break; + } + + if (azt2316a->cur_mpu401_enabled) + temp += 1 << 3; + + switch (cd_type) { + case 0: // disabled + //do nothing + temp += 0 << 5; + break; + case 1: // panasonic + temp += 1 << 5; + break; + case 2: // mitsumi/sony/aztech + temp += 2 << 5; + break; + case 3: // all enabled + temp += 3 << 5; + break; + case 4: // unused + temp += 4 << 5; + break; + case 5: // unused + temp += 5 << 5; + break; + case 6: // unused + temp += 6 << 5; + break; + case 7: // unused + temp += 7 << 5; + break; + + default: + break; + } + + switch (azt2316a->cur_dma) { + case 0: + temp += 1 << 24; + break; + case 1: + temp += 1 << 25; + break; + case 3: + temp += 1 << 26; + break; + default: + break; + } + + switch (azt2316a->cur_wss_dma16) { + case 5: + temp += 1 << 27; + break; + case 6: + temp += 1 << 28; + break; + case 7: + temp += 1 << 29; + break; + default: + break; + } + + switch (azt2316a->cur_mpu401_irq) { + case 2: + temp += 1 << 12; + break; + case 5: + temp += 1 << 13; + break; + case 7: + temp += 1 << 14; + break; + case 10: + temp += 1 << 15; + break; + + default: + break; + } + + switch (cd_irq) { + case 0: // disabled + // do nothing + break; + case 11: + temp += 1 << 20; + break; + case 12: + temp += 1 << 21; + break; + case 15: + temp += 1 << 22; + break; + + default: + break; + } + + azt2316a->config_word = temp; + aztech_log(azt2316a->log, "Aztech PR16 Config Word Create: %08X\n", temp); +} + + +static void +azt1605_create_config_word(void *priv) +{ + azt2316a_t *azt2316a = (azt2316a_t *) priv; + uint32_t temp = 0; + + /* not implemented / hardcoded */ + uint8_t cd_type = 0; /* TODO: see if the cd-rom was originally connected there on the real machines emulated by 86Box (Packard Bell Legend 100CD, Itautec Infoway Multimidia, etc) */ + uint8_t cd_dma8 = -1; + uint8_t cd_irq = 0; + + switch (azt2316a->cur_addr) { + case 0x220: + // do nothing + break; + case 0x240: + temp += 1 << 0; + break; default: break; } @@ -329,9 +535,6 @@ azt1605_create_config_word(void *priv) switch (azt2316a->cur_wss_addr) { case 0x530: // do nothing -#if 0 - temp += 0 << 16; -#endif break; case 0x604: temp += 1 << 16; @@ -350,15 +553,12 @@ azt1605_create_config_word(void *priv) if (azt2316a->cur_wss_enabled) temp += 1 << 18; - if (game_enable) + if (azt2316a->gameport_enabled) temp += 1 << 4; switch (azt2316a->cur_mpu401_addr) { case 0x300: // do nothing -#if 0 - temp += 0 << 2; -#endif break; case 0x330: temp += 1 << 2; @@ -372,9 +572,8 @@ azt1605_create_config_word(void *priv) temp += 1 << 3; switch (cd_type) { - case 0: /* disabled - do nothing - temp += 0 << 5; */ + case 0: // disabled + // do nothing break; case 1: // panasonic temp += 1 << 5; @@ -403,9 +602,8 @@ azt1605_create_config_word(void *priv) } switch (cd_dma8) { - case 0xFF: /* -1 - do nothing - temp += 0 << 22;*/ + case 0xFF: // -1 + //do nothing break; case 0: temp += 1 << 22; @@ -468,7 +666,6 @@ azt2316a_create_config_word(void *priv) uint32_t temp = 0; /* not implemented / hardcoded */ - uint8_t game_enable = 1; uint16_t cd_addr = 0x310; uint8_t cd_type = 0; /* TODO: see if the cd-rom was originally connected there on the real machines emulated by 86Box (Packard Bell Legend 100CD, Itautec Infoway Multimidia, etc) */ uint8_t cd_dma8 = -1; @@ -480,24 +677,18 @@ azt2316a_create_config_word(void *priv) return; } + if (azt2316a->type == SB_SUBTYPE_CLONE_AZTPR16_0X09) { + aztpr16_create_config_word(priv); + return; + } + switch (azt2316a->cur_addr) { case 0x220: // do nothing -#if 0 - temp += 0 << 0; -#endif break; case 0x240: temp += 1 << 0; break; -#if 0 - case 0x260: // TODO: INVALID? - temp += 2 << 0; - break; - case 0x280: // TODO: INVALID? - temp += 3 << 0; - break; -#endif default: break; } @@ -521,13 +712,6 @@ azt2316a_create_config_word(void *priv) } switch (azt2316a->cur_dma) { -#if 0 - // TODO: INVALID? - case 0xFF: // -1 - // do nothing - //temp += 0 << 6; - break; -#endif case 0: temp += 1 << 6; break; @@ -545,9 +729,6 @@ azt2316a_create_config_word(void *priv) switch (azt2316a->cur_wss_addr) { case 0x530: // do nothing -#if 0 - temp += 0 << 8; -#endif break; case 0x604: temp += 1 << 8; @@ -564,14 +745,11 @@ azt2316a_create_config_word(void *priv) } if (azt2316a->cur_wss_enabled) temp += 1 << 10; - if (game_enable) + if (azt2316a->gameport_enabled) temp += 1 << 11; switch (azt2316a->cur_mpu401_addr) { case 0x300: // do nothing -#if 0 - temp += 0 << 12; -#endif break; case 0x330: temp += 1 << 12; @@ -587,9 +765,6 @@ azt2316a_create_config_word(void *priv) switch (cd_addr) { case 0x310: // do nothing -#if 0 - temp += 0 << 14; -#endif break; case 0x320: temp += 1 << 14; @@ -607,9 +782,6 @@ azt2316a_create_config_word(void *priv) switch (cd_type) { case 0: /* disabled */ // do nothing -#if 0 - temp += 0 << 16; */ -#endif break; case 1: /* panasonic */ temp += 1 << 16; @@ -638,18 +810,15 @@ azt2316a_create_config_word(void *priv) } switch (cd_dma8) { - case 0xFF: /* -1 - do nothing - temp += 0 << 20; */ + case 0xFF: // -1 + //do nothing break; case 0: temp += 1 << 20; break; -#if 0 - case 1: // TODO: INVALID? + case 1: temp += 2 << 20; break; -#endif case 3: temp += 3 << 20; break; @@ -659,9 +828,8 @@ azt2316a_create_config_word(void *priv) } switch (cd_dma16) { - case 0xFF: /* -1 - do nothing - temp += 0 << 22; */ + case 0xFF: // -1 + //do nothing break; case 5: temp += 1 << 22; @@ -789,41 +957,176 @@ azt2316a_config_read(uint16_t addr, void *priv) /* Some WSS config here + config change enable bit (setting bit 7 and writing back) */ - if (addr == (azt2316a->cur_addr + 0x404)) { - /* TODO: what is the real meaning of the read value? - I got a mention of bit 0x10 for WSS from disassembling the source - code of the driver, and when playing with the I/O ports on real - hardware after doing some configuration, but didn't dig into it. - Bit 0x08 seems to be a busy flag and generates a timeout - (continuous re-reading when initializing windows 98) */ - temp = azt2316a->cur_mode ? 0x07 : 0x0F; - if (azt2316a->config_word_unlocked) { - temp |= 0x80; - } - } else { - // Rest of config. These are documented in the Linux driver. - switch (addr & 0x3) { - case 0: - temp = azt2316a->config_word & 0xFF; + if (addr == (azt2316a->cur_addr + 0x404)) { + /* TODO: what is the real meaning of the read value? + I got a mention of bit 0x10 for WSS from disassembling the source + code of the driver, and when playing with the I/O ports on real + hardware after doing some configuration, but didn't dig into it. + Bit 0x08 seems to be a busy flag and generates a timeout + (continuous re-reading when initializing windows 98) */ + temp = azt2316a->cur_mode ? 0x07 : 0x0F; + if (azt2316a->config_word_unlocked) { + temp |= 0x80; + } + } else { + // Rest of config. These are documented in the Linux driver. + switch (addr & 0x3) { + case 0: + temp = azt2316a->config_word & 0xFF; + break; + case 1: + temp = (azt2316a->config_word >> 8); + break; + case 2: + temp = (azt2316a->config_word >> 16); + break; + case 3: + temp = (azt2316a->config_word >> 24); + break; + + default: + break; + } + } + + aztech_log(azt2316a->log, "Aztech 2316 Config Word Read: (%04X) = %02X\n", addr, temp); + + return temp; +} + +static void +aztpr16_config_write(uint16_t addr, uint8_t val, void *priv) +{ + azt2316a_t *azt2316a = (azt2316a_t *) priv; + uint8_t temp; + + aztech_log(azt2316a->log, "Aztech PR16 Config Word Write: (%04X) = %02X\n", addr, val); + + if (addr == (azt2316a->cur_addr + 0x404)) { + if (val & 0x80) + azt2316a->config_word_unlocked = 1; + else + azt2316a->config_word_unlocked = 0; + } else if (azt2316a->config_word_unlocked) { + if (val == 0xFF) { + return; + } + switch (addr & 3) { + case 0: + azt2316a->config_word = (azt2316a->config_word & 0xFFFFFF00) | val; + + temp = val & 3; + if (temp == 0) + azt2316a->cur_addr = 0x220; + else if (temp == 1) + azt2316a->cur_addr = 0x240; + else if (temp == 2) + azt2316a->cur_addr = 0x260; + else if (temp == 3) + azt2316a->cur_addr = 0x280; + + if (val & 0x4) + azt2316a->cur_mpu401_addr = 0x330; + else + azt2316a->cur_mpu401_addr = 0x300; + + if (val & 0x8) + azt2316a->cur_mpu401_enabled = 1; + else + azt2316a->cur_mpu401_enabled = 0; + + if (val & 0x10) + azt2316a->gameport_enabled = 1; + else + azt2316a->gameport_enabled = 0; break; case 1: - temp = (azt2316a->config_word >> 8); + azt2316a->config_word = (azt2316a->config_word & 0xFFFF00FF) | (val << 8); + + if (val & 0x1) + azt2316a->cur_irq = 2; + else if (val & 0x2) + azt2316a->cur_irq = 5; + else if (val & 0x4) + azt2316a->cur_irq = 7; + else if (val & 0x8) + azt2316a->cur_irq = 10; + /* else undefined? */ + + if (val & 0x10) + azt2316a->cur_mpu401_irq = 2; + else if (val & 0x20) + azt2316a->cur_mpu401_irq = 5; + else if (val & 0x40) + azt2316a->cur_mpu401_irq = 7; + else if (val & 0x80) + azt2316a->cur_mpu401_irq = 10; + /* else undefined? */ break; case 2: - temp = (azt2316a->config_word >> 16); + azt2316a->config_word = (azt2316a->config_word & 0xFF00FFFF) | (val << 16); + + io_removehandler(azt2316a->cur_wss_addr, 0x0004, azt2316a_wss_read, NULL, NULL, azt2316a_wss_write, NULL, NULL, azt2316a); + io_removehandler(azt2316a->cur_wss_addr + 0x0004, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &azt2316a->ad1848); + + temp = val & 0x3; + if (temp == 0) + azt2316a->cur_wss_addr = 0x530; + else if (temp == 1) + azt2316a->cur_wss_addr = 0x604; + else if (temp == 2) + azt2316a->cur_wss_addr = 0xE80; + else if (temp == 3) + azt2316a->cur_wss_addr = 0xF40; + + io_sethandler(azt2316a->cur_wss_addr, 0x0004, azt2316a_wss_read, NULL, NULL, azt2316a_wss_write, NULL, NULL, azt2316a); + io_sethandler(azt2316a->cur_wss_addr + 0x0004, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &azt2316a->ad1848); + + /* no actual effect */ + if (val & 0x4) + azt2316a->cur_wss_enabled = 1; + else + azt2316a->cur_wss_enabled = 0; break; case 3: - temp = (azt2316a->config_word >> 24); + azt2316a->config_word = (azt2316a->config_word & 0x00FFFFFF) | (val << 24); + + if (val & 0x01) { + azt2316a->cur_dma = 0; + azt2316a->cur_wss_dma = 0; + } else if (val & 0x02) { + azt2316a->cur_dma = 1; + azt2316a->cur_wss_dma = 1; + } else if (val & 0x04) { + azt2316a->cur_dma = 3; + azt2316a->cur_wss_dma = 3; + } + + if (val & 0x08) + azt2316a->cur_wss_dma16 = 5; + else if (val & 0x10) + azt2316a->cur_wss_dma16 = 6; + else if (val & 0x20) + azt2316a->cur_wss_dma16 = 7; break; default: break; } - } + /* update sbprov2 configs */ + sb_dsp_setaddr(&azt2316a->sb->dsp, azt2316a->cur_addr); + sb_dsp_setirq(&azt2316a->sb->dsp, azt2316a->cur_irq); + sb_dsp_setdma8(&azt2316a->sb->dsp, azt2316a->cur_dma); - aztech_log(azt2316a->log, "Aztech 2316 Config Word Read: (%04X) = %02X\n", addr, temp); + mpu401_change_addr(azt2316a->mpu, azt2316a->cur_mpu401_addr); + mpu401_setirq(azt2316a->mpu, azt2316a->cur_mpu401_irq); - return temp; + ad1848_setdma(&azt2316a->ad1848, azt2316a->cur_wss_dma); + ad1848_setirq(&azt2316a->ad1848, azt2316a->cur_irq); + azt2316a->cur_wss_irq = azt2316a->cur_irq; + + gameport_remap(azt2316a->gameport, (azt2316a->gameport_enabled) ? 0x200 : 0x00); + } } static void @@ -840,7 +1143,7 @@ azt1605_config_write(uint16_t addr, uint8_t val, void *priv) else azt2316a->config_word_unlocked = 0; } else if (azt2316a->config_word_unlocked) { - if (val == 0xFF) { /* TODO: check if this still happens on eeprom.sys after having more complete emulation! */ + if (val == 0xFF) { return; } switch (addr & 3) { @@ -852,12 +1155,7 @@ azt1605_config_write(uint16_t addr, uint8_t val, void *priv) azt2316a->cur_addr = 0x220; else if (temp == 1) azt2316a->cur_addr = 0x240; -#if 0 - else if (temp == 2) - azt2316a->cur_addr = 0x260; // TODO: INVALID - else if (temp == 3) - azt2316a->cur_addr = 0x280; // TODO: INVALID -#endif + if (val & 0x4) azt2316a->cur_mpu401_addr = 0x330; else @@ -867,6 +1165,11 @@ azt1605_config_write(uint16_t addr, uint8_t val, void *priv) azt2316a->cur_mpu401_enabled = 1; else azt2316a->cur_mpu401_enabled = 0; + + if (val & 0x10) + azt2316a->gameport_enabled = 1; + else + azt2316a->gameport_enabled = 0; break; case 1: azt2316a->config_word = (azt2316a->config_word & 0xFFFF00FF) | (val << 8); @@ -929,6 +1232,8 @@ azt1605_config_write(uint16_t addr, uint8_t val, void *priv) mpu401_change_addr(azt2316a->mpu, azt2316a->cur_mpu401_addr); mpu401_setirq(azt2316a->mpu, azt2316a->cur_mpu401_irq); + + gameport_remap(azt2316a->gameport, (azt2316a->gameport_enabled) ? 0x200 : 0x00); } } @@ -1000,6 +1305,11 @@ azt2316a_config_write(uint16_t addr, uint8_t val, void *priv) else azt2316a->cur_wss_enabled = 0; + if (val & 0x8) + azt2316a->gameport_enabled = 1; + else + azt2316a->gameport_enabled = 0; + if (val & 0x10) azt2316a->cur_mpu401_addr = 0x330; else @@ -1037,6 +1347,8 @@ azt2316a_config_write(uint16_t addr, uint8_t val, void *priv) mpu401_change_addr(azt2316a->mpu, azt2316a->cur_mpu401_addr); mpu401_setirq(azt2316a->mpu, azt2316a->cur_mpu401_irq); + + gameport_remap(azt2316a->gameport, (azt2316a->gameport_enabled) ? 0x200 : 0x00); } } @@ -1062,6 +1374,33 @@ azt2316a_enable_wss(uint8_t enable, void *priv) } } +void +aztpr16_wss_mode(uint8_t mode, void *priv) +{ + azt2316a_t *azt2316a = (azt2316a_t *) priv; + + sound_set_cd_audio_filter(NULL, NULL); + + if (mode) { + azt2316a->cur_mode = 1; + sound_set_cd_audio_filter(ad1848_filter_cd_audio, &azt2316a->ad1848); + azt2316a->sb->opl_mixer = azt2316a; + azt2316a->sb->opl_mix = azt1605_filter_opl; + } + else { + azt2316a->cur_mode = 0; + sound_set_cd_audio_filter(sbpro_filter_cd_audio, azt2316a->sb); + azt2316a->sb->opl_mixer = NULL; + azt2316a->sb->opl_mix = NULL; + } + + if (mode == 0x03) + ad1848_setdma(&azt2316a->ad1848, azt2316a->cur_wss_dma16); + else + ad1848_setdma(&azt2316a->ad1848, azt2316a->cur_wss_dma); + +} + static void azt2316a_get_buffer(int32_t *buffer, int len, void *priv) { @@ -1097,6 +1436,8 @@ azt_init(const device_t *info) fn = "azt1605.nvr"; } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { fn = "azt2316a.nvr"; + } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZTPR16_0X09) { + fn = "aztpr16.nvr"; } /* config */ @@ -1121,13 +1462,13 @@ azt_init(const device_t *info) if (!loaded_from_eeprom) { if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { - read_eeprom[0] = 0x00; - read_eeprom[1] = 0x00; - read_eeprom[2] = 0x00; - read_eeprom[3] = 0x00; - read_eeprom[4] = 0x00; - read_eeprom[5] = 0x00; - read_eeprom[6] = 0x00; + read_eeprom[0] = 0xee; /* SB Voice mixer value */ + read_eeprom[1] = 0x00; /* SB Mic mixer value (bits 2-0) */ + read_eeprom[2] = 0x00; /* SB Record Source */ + read_eeprom[3] = 0xee; /* SB Master mixer value */ + read_eeprom[4] = 0xee; /* SB FM mixer value */ + read_eeprom[5] = 0xee; /* SB CD mixer value */ + read_eeprom[6] = 0x00; /* SB Line mixer value */ read_eeprom[7] = 0x00; read_eeprom[8] = 0x00; read_eeprom[9] = 0x00; @@ -1154,6 +1495,28 @@ azt_init(const device_t *info) read_eeprom[13] = 0x14; read_eeprom[14] = 0x04; read_eeprom[15] = 0xFF; /* SBPro Master volume (EMUTSR) */ + } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZTPR16_0X09) { + read_eeprom[0] = 0x00; + read_eeprom[1] = 0x00; + read_eeprom[2] = 0x00; + read_eeprom[3] = 0x3f; /* Master Volume L */ + read_eeprom[4] = 0x3f; /* Master Volume R */ + read_eeprom[5] = 0x1f; /* Wave Volume L */ + read_eeprom[6] = 0x1f; /* Wave Volume R */ + read_eeprom[7] = 0x1f; /* FM Volume L */ + read_eeprom[8] = 0x1f; /* FM Volume R */ + read_eeprom[9] = 0x1f; /* CD Volume L */ + read_eeprom[10] = 0x1f; /* CD Volume R */ + read_eeprom[11] = 0x1f; /* Line Volume L */ + read_eeprom[12] = 0x1f; /* Line Volume R */ + read_eeprom[13] = 0x1f; /* Mic Volume L */ + read_eeprom[14] = 0x1f; /* Mic Volume R */ + read_eeprom[15] = 0x1f; /* WSynth Volume L */ + read_eeprom[16] = 0x1f; /* WSynth Volume R */ + read_eeprom[32] = 0x1c; + read_eeprom[33] = 0x12; + read_eeprom[34] = 0x04; + read_eeprom[35] = 0x02; } } @@ -1218,6 +1581,11 @@ azt_init(const device_t *info) else azt2316a->cur_wss_enabled = 0; + if (azt2316a->config_word & (1 << 11)) + azt2316a->gameport_enabled = 1; + else + azt2316a->gameport_enabled = 0; + if (azt2316a->config_word & (1 << 12)) azt2316a->cur_mpu401_addr = 0x330; else @@ -1267,6 +1635,11 @@ azt_init(const device_t *info) else azt2316a->cur_mpu401_enabled = 0; + if (azt2316a->config_word & (1 << 4)) + azt2316a->gameport_enabled = 1; + else + azt2316a->gameport_enabled = 0; + if (azt2316a->config_word & (1 << 8)) azt2316a->cur_irq = 9; else if (azt2316a->config_word & (1 << 9)) @@ -1312,18 +1685,122 @@ azt_init(const device_t *info) azt2316a->cur_wss_enabled = 0; // these are not present on the EEPROM - azt2316a->cur_dma = device_get_config_int("sb_dma8"); // TODO: investigate TSR to make this work with it - there is no software configurable DMA8? + azt2316a->cur_dma = device_get_config_int("sb_dma8"); azt2316a->cur_wss_irq = device_get_config_int("wss_irq"); azt2316a->cur_wss_dma = device_get_config_int("wss_dma"); azt2316a->cur_mode = 0; + } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZTPR16_0X09) { + azt2316a->config_word = read_eeprom[32] + (read_eeprom[33] << 8) + (read_eeprom[34] << 16) + (read_eeprom[35] << 24); + aztech_log(azt2316a->log, "AZTPR16 Config Word = %08X\n", azt2316a->config_word); + + switch (azt2316a->config_word & (3 << 0)) { + case 0: + azt2316a->cur_addr = 0x220; + break; + case 1: + azt2316a->cur_addr = 0x240; + break; + case 2: + azt2316a->cur_addr = 0x260; + break; + case 3: + azt2316a->cur_addr = 0x280; + break; + default: + fatal("AZTPR16: invalid sb addr in config word %08X\n", azt2316a->config_word); + break; + } + + if (azt2316a->config_word & (1 << 2)) + azt2316a->cur_mpu401_addr = 0x330; + else + azt2316a->cur_mpu401_addr = 0x300; + + if (azt2316a->config_word & (1 << 3)) + azt2316a->cur_mpu401_enabled = 1; + else + azt2316a->cur_mpu401_enabled = 0; + + if (azt2316a->config_word & (1 << 4)) + azt2316a->gameport_enabled = 1; + else + azt2316a->gameport_enabled = 0; + + if (azt2316a->config_word & (1 << 8)) + azt2316a->cur_irq = 2; + else if (azt2316a->config_word & (1 << 9)) + azt2316a->cur_irq = 5; + else if (azt2316a->config_word & (1 << 10)) + azt2316a->cur_irq = 7; + else if (azt2316a->config_word & (1 << 11)) + azt2316a->cur_irq = 10; + else + fatal("AZTPR16: invalid sb irq in config word %08X\n", azt2316a->config_word); + + if (azt2316a->config_word & (1 << 12)) + azt2316a->cur_mpu401_irq = 2; + else if (azt2316a->config_word & (1 << 13)) + azt2316a->cur_mpu401_irq = 5; + else if (azt2316a->config_word & (1 << 14)) + azt2316a->cur_mpu401_irq = 7; + else if (azt2316a->config_word & (1 << 15)) + azt2316a->cur_mpu401_irq = 10; + else + fatal("AZTPR16: invalid mpu401 irq in config word %08X\n", azt2316a->config_word); + switch (azt2316a->config_word & (3 << 16)) { + case 0: + azt2316a->cur_wss_addr = 0x530; + break; + case 1 << 16: + azt2316a->cur_wss_addr = 0x604; + break; + case 2 << 16: + azt2316a->cur_wss_addr = 0xE80; + break; + case 3 << 16: + azt2316a->cur_wss_addr = 0xF40; + break; + default: + fatal("AZTPR16: invalid wss addr in config word %08X\n", azt2316a->config_word); + break; + } + + if (azt2316a->config_word & (1 << 18)) + azt2316a->cur_wss_enabled = 1; + else + azt2316a->cur_wss_enabled = 0; + + if (azt2316a->config_word & (1 << 24)) + azt2316a->cur_dma = 0; + else if (azt2316a->config_word & (1 << 25)) + azt2316a->cur_dma = 1; + else if (azt2316a->config_word & (1 << 26)) + azt2316a->cur_dma = 3; + + if (azt2316a->config_word & (1 << 27)) + azt2316a->cur_wss_dma16 = 5; + else if (azt2316a->config_word & (1 << 28)) + azt2316a->cur_wss_dma16 = 6; + else if (azt2316a->config_word & (1 << 29)) + azt2316a->cur_wss_dma16 = 7; + + // these are not present on the EEPROM + azt2316a->cur_wss_irq = azt2316a->cur_irq; + azt2316a->cur_wss_dma = azt2316a->cur_dma; + azt2316a->cur_mode = 0; } - addr_setting = device_get_config_hex16("addr"); - if (addr_setting) - azt2316a->cur_addr = addr_setting; + if (azt2316a->type != SB_SUBTYPE_CLONE_AZTPR16_0X09) { + addr_setting = device_get_config_hex16("addr"); + if (addr_setting) + azt2316a->cur_addr = addr_setting; + } /* wss part */ - ad1848_init(&azt2316a->ad1848, device_get_config_int("codec")); + if (azt2316a->type == SB_SUBTYPE_CLONE_AZTPR16_0X09) + ad1848_init(&azt2316a->ad1848, AD1848_TYPE_DEFAULT); /* AZTPR16 has an internal AD1848-compatible (non-Mode 2 capable) WSS codec */ + else + ad1848_init(&azt2316a->ad1848, device_get_config_int("codec")); if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) ad1848_set_cd_audio_channel(&azt2316a->ad1848, (device_get_config_int("codec") == AD1848_TYPE_CS4248) ? AD1848_AUX1 : AD1848_LINE_IN); else @@ -1334,6 +1811,8 @@ azt_init(const device_t *info) if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) io_sethandler(azt2316a->cur_addr + 0x0400, 0x0040, azt2316a_config_read, NULL, NULL, azt2316a_config_write, NULL, NULL, azt2316a); + else if (azt2316a->type == SB_SUBTYPE_CLONE_AZTPR16_0X09) + io_sethandler(azt2316a->cur_addr + 0x0400, 0x0010, azt1605_config_read, NULL, NULL, aztpr16_config_write, NULL, NULL, azt2316a); else /* Aztech 1605 only needs 62x/64x */ io_sethandler(azt2316a->cur_addr + 0x0400, 0x0010, azt1605_config_read, NULL, NULL, azt1605_config_write, NULL, NULL, azt2316a); io_sethandler(azt2316a->cur_wss_addr, 0x0004, azt2316a_wss_read, NULL, NULL, azt2316a_wss_write, NULL, NULL, azt2316a); @@ -1395,6 +1874,17 @@ azt_init(const device_t *info) if (device_get_config_int("receive_input")) midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &azt2316a->sb->dsp); + /* Restore SBPro mixer settings from EEPROM on AZT2316A cards */ + if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { + azt2316a->sb->mixer_sbpro.regs[0x04] = read_eeprom[0]; /* SBPro Voice */ + azt2316a->sb->mixer_sbpro.regs[0x0a] = read_eeprom[1]; /* SBPro Mic */ + azt2316a->sb->mixer_sbpro.regs[0x0c] = read_eeprom[2]; /* SBPro Record Source */ + azt2316a->sb->mixer_sbpro.regs[0x22] = read_eeprom[3]; /* SBPro Master */ + azt2316a->sb->mixer_sbpro.regs[0x26] = read_eeprom[4]; /* SBPro FM */ + azt2316a->sb->mixer_sbpro.regs[0x28] = read_eeprom[5]; /* SBPro CD */ + azt2316a->sb->mixer_sbpro.regs[0x2e] = read_eeprom[6]; /* SBPro Line */ + } + /* Restore WSS mixer settings from EEPROM on AZT1605 cards */ if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) { azt2316a->ad1848.regs[0] = read_eeprom[0]; /* WSS ADC L */ @@ -1409,6 +1899,72 @@ azt_init(const device_t *info) azt2316a->ad1848.regs[19] = read_eeprom[9]; /* CS4231 LINE/SB Voice R */ azt2316a->ad1848.regs[26] = read_eeprom[10]; /* CS4231 Mic */ } + /* Restore mixer settings from EEPROM on AZTPR16 cards */ + if (azt2316a->type == SB_SUBTYPE_CLONE_AZTPR16_0X09) { + azt2316a->sb->mixer_sbpro.regs[0x84] = read_eeprom[3]; /* Master L */ + azt2316a->sb->mixer_sbpro.regs[0x86] = read_eeprom[4]; /* Master R */ + azt2316a->sb->mixer_sbpro.regs[0x88] = read_eeprom[5]; /* Wave L */ + azt2316a->sb->mixer_sbpro.regs[0x8a] = read_eeprom[6]; /* Wave R */ + azt2316a->sb->mixer_sbpro.regs[0x8c] = read_eeprom[7]; /* FM L */ + azt2316a->sb->mixer_sbpro.regs[0x8e] = read_eeprom[8]; /* FM R */ + azt2316a->sb->mixer_sbpro.regs[0xa0] = read_eeprom[9]; /* CD L */ + azt2316a->sb->mixer_sbpro.regs[0xa2] = read_eeprom[10]; /* CD R */ + azt2316a->sb->mixer_sbpro.regs[0xa4] = read_eeprom[11]; /* Line L */ + azt2316a->sb->mixer_sbpro.regs[0xa6] = read_eeprom[12]; /* Line R */ + azt2316a->sb->mixer_sbpro.regs[0xa8] = read_eeprom[13]; /* Mic L */ + azt2316a->sb->mixer_sbpro.regs[0xaa] = read_eeprom[14]; /* Mic R */ + azt2316a->sb->mixer_sbpro.regs[0xac] = read_eeprom[15]; /* WSynth L */ + azt2316a->sb->mixer_sbpro.regs[0xae] = read_eeprom[16]; /* WSynth R */ + azt2316a->sb->mixer_sbpro.regs[0xc2] = read_eeprom[18]; /* Speaker */ + azt2316a->sb->mixer_sbpro.regs[0xc4] = read_eeprom[19]; /* Bass */ + azt2316a->sb->mixer_sbpro.regs[0xc6] = read_eeprom[20]; /* Treble */ + azt2316a->sb->mixer_sbpro.regs[0xc8] = read_eeprom[21]; /* I/O settings byte 1 */ + azt2316a->sb->mixer_sbpro.regs[0xca] = read_eeprom[22]; /* I/O settings byte 2 */ + azt2316a->sb->mixer_sbpro.regs[0xcc] = read_eeprom[23]; /* I/O settings byte 3 */ + azt2316a->sb->mixer_sbpro.regs[0xce] = read_eeprom[24]; /* I/O settings byte 4 */ + azt2316a->sb->mixer_sbpro.regs[0xe0] = read_eeprom[25]; /* Record Gain R */ + azt2316a->sb->mixer_sbpro.regs[0xe2] = read_eeprom[26]; /* Record Gain L */ + azt2316a->sb->mixer_sbpro.regs[0xe4] = read_eeprom[27]; /* Output Gain L */ + azt2316a->sb->mixer_sbpro.regs[0xe6] = read_eeprom[28]; /* Output Gain L */ + azt2316a->sb->mixer_sbpro.regs[0xe8] = read_eeprom[29]; /* Output Gain L */ + + /* Sane initial WSS values */ + azt2316a->ad1848.regs[0] = 0x08; /* WSS ADC L */ + azt2316a->ad1848.regs[1] = 0x08; /* WSS ADC R */ + azt2316a->ad1848.regs[2] = 0x08; /* WSS AUX1/CD L */ + azt2316a->ad1848.regs[3] = 0x08; /* WSS AUX1/CD R */ + azt2316a->ad1848.regs[4] = 0x08; /* WSS AUX2/FM L */ + azt2316a->ad1848.regs[5] = 0x08; /* WSS AUX2/FM R */ + azt2316a->ad1848.regs[6] = 0x08; /* WSS DAC L */ + azt2316a->ad1848.regs[7] = 0x08; /* WSS DAC R */ + + /* Set up CD volume table */ + uint8_t c; + double attenuation; + + for (c = 0; c < 32; c++) { + attenuation = 12.0; + if (c & 0x01) + attenuation -= 1.5; + if (c & 0x02) + attenuation -= 3.0; + if (c & 0x04) + attenuation -= 6.0; + if (c & 0x08) + attenuation -= 12.0; + if (c & 0x10) + attenuation -= 24.0; + + attenuation = pow(10, attenuation / 10); + + aztpr16_vols_5bits[c] = (attenuation * 65536); + } + + aztpr16_update_mixer(azt2316a); + } + + azt2316a->gameport = gameport_add(&gameport_pnp_device); + gameport_remap(azt2316a->gameport, (azt2316a->gameport_enabled) ? 0x200: 0x00); return azt2316a; } @@ -1425,6 +1981,8 @@ azt_close(void *priv) fn = "azt1605.nvr"; } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZT2316A_0X11) { fn = "azt2316a.nvr"; + } else if (azt2316a->type == SB_SUBTYPE_CLONE_AZTPR16_0X09) { + fn = "aztpr16.nvr"; } /* always save to eeprom (recover from bad values) */ @@ -1434,7 +1992,6 @@ azt_close(void *priv) checksum += azt2316a->sb->dsp.azt_eeprom[i]; fwrite(azt2316a->sb->dsp.azt_eeprom, AZTECH_EEPROM_SIZE, 1, fp); - // TODO: confirm any models saving mixer settings to EEPROM and implement reading back // TODO: should remember to save wss duplex setting if 86Box has voice recording implemented in the future? Also, default azt2316a->wss_config // TODO: azt2316a->cur_mode is not saved to EEPROM? fwrite(&checksum, sizeof(checksum), 1, fp); @@ -1463,6 +2020,45 @@ azt_speed_changed(void *priv) sb_speed_changed(azt2316a->sb); } +static const device_config_t aztpr16_config[] = { + // clang-format off + { + .name = "opl", + .description = "Enable OPL", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { + .name = "receive_input", + .description = "Receive MIDI input", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { + .name = "receive_input401", + .description = "Receive MIDI input (MPU-401)", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + static const device_config_t azt1605_config[] = { // clang-format off { @@ -1670,7 +2266,7 @@ static const device_config_t azt2316a_config[] = { }, { .name = "receive_input401", - .description = "Receive MIDI input", + .description = "Receive MIDI input (MPU-401)", .type = CONFIG_BINARY, .default_string = NULL, .default_int = 0, @@ -1710,3 +2306,17 @@ const device_t azt1605_device = { .force_redraw = NULL, .config = azt1605_config }; + +const device_t aztpr16_device = { + .name = "Aztech Sound Galaxy Pro 16 (AZTPR16)", + .internal_name = "aztpr16", + .flags = DEVICE_ISA16, + .local = SB_SUBTYPE_CLONE_AZTPR16_0X09, + .init = azt_init, + .close = azt_close, + .reset = NULL, + .available = NULL, + .speed_changed = azt_speed_changed, + .force_redraw = NULL, + .config = aztpr16_config +}; diff --git a/src/sound/snd_covox.c b/src/sound/snd_covox.c index c7e32c7dc02..0d6b1dbc1b0 100644 --- a/src/sound/snd_covox.c +++ b/src/sound/snd_covox.c @@ -243,7 +243,7 @@ static const device_config_t voicemasterkey_config[] = { .description = "Address", .type = CONFIG_HEX16, .default_string = NULL, - .default_int = 0x388, + .default_int = 0x22f, .file_filter = NULL, .spinner = { 0 }, .selection = { diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index 4fd630e07c9..b9004454e8c 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -1203,7 +1203,7 @@ const device_t cs4236b_device = { }; const device_t cs4236b_onboard_device = { - .name = "Crystal CS4236B", + .name = "Crystal CS4236B (On-Board)", .internal_name = "cs4236b", .flags = DEVICE_ISA16, .local = CRYSTAL_CS4236B | CRYSTAL_NOEEPROM, diff --git a/src/sound/snd_optimc.c b/src/sound/snd_optimc.c index 7c72104aec2..5ea5d773c46 100644 --- a/src/sound/snd_optimc.c +++ b/src/sound/snd_optimc.c @@ -38,7 +38,9 @@ #include <86box/mem.h> #include <86box/rom.h> #include <86box/plat_unused.h> +#include <86box/hdc.h> #include <86box/isapnp.h> +#include <86box/hdc_ide.h> #include <86box/log.h> #define PNP_ROM_OPTI931 "roms/sound/opti931/adsrom.bin" @@ -889,7 +891,8 @@ opti931_pnp_config_changed(uint8_t ld, isapnp_device_config_t *config, void *pri optimc_log(optimc->log, "PnP Config changed\n"); switch (ld) { - case 0: /* Aux Device */ + case 0: /* IDE CD-ROM */ + ide_pnp_config_changed_opti931(0, config, (void *) 3); break; case 1: /* WSS/OPL3/SBPro/Control regs */ if (optimc->cur_wss_addr) { @@ -1155,6 +1158,11 @@ optimc_init(const device_t *info) /* Set up ISAPnP handlers to intercept Read Data port changes */ io_sethandler(0x279, 0x0001, NULL, NULL, NULL, opti931_isapnp_write, NULL, NULL, optimc); io_sethandler(0xA79, 0x0001, NULL, NULL, NULL, opti931_isapnp_write, NULL, NULL, optimc); + + /* Add ISAPnP quaternary IDE controller */ + device_add(&ide_qua_pnp_device); + other_ide_present++; + ide_remove_handlers(3); } /* OPTi 930 DOS sound test utility starts DMA playback without setting a time constant likely making */ @@ -1277,7 +1285,7 @@ const device_t mirosound_pcm10_device = { }; const device_t opti_82c930_device = { - .name = "OPTi 82c930", + .name = "OPTi 82C930", .internal_name = "opti_82c930", .flags = DEVICE_ISA16, .local = OPTI_930 | OPTIMC_CS4231, @@ -1291,7 +1299,7 @@ const device_t opti_82c930_device = { }; const device_t opti_82c931_device = { - .name = "OPTi 82c931", + .name = "OPTi 82C931", .internal_name = "opti_82c931", .flags = DEVICE_ISA16, .local = OPTI_930 | OPTIMC_CS4231 | OPTI_931, diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index f041ebb8c2b..c2193869d1d 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -43,6 +43,7 @@ #include <86box/timer.h> #include <86box/snd_sb.h> #include <86box/plat_unused.h> +#include <86box/snd_azt2316a.h> #define SB_1 0 #define SB_15 1 @@ -863,6 +864,76 @@ sb_ct1345_mixer_write(uint16_t addr, uint8_t val, void *priv) mixer->regs[0x26] = mixer->regs[0x28] = 0xee; mixer->regs[0x2e] = 0x00; sb_dsp_set_stereo(&sb->dsp, mixer->regs[0x0e] & 2); + } else if (sb->dsp.sb_subtype == SB_SUBTYPE_CLONE_AZTPR16_0X09) { + mixer->regs[mixer->index] = val; + sb_log("sb_ct1345: Register WRITE, AZTPR16: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + aztpr16_update_mixer(sb->dsp.parent); + + switch (mixer->index) { + /* Compatibility: chain registers 0x02 and 0x22 as well as 0x06 and 0x26 */ + case 0x02: + case 0x06: + case 0x08: + mixer->regs[mixer->index + 0x20] = ((val & 0xe) << 4) | (val & 0xe); + break; + + case 0x22: + case 0x26: + case 0x28: + mixer->regs[mixer->index - 0x20] = (val & 0xe); + break; + + /* More compatibility: + SoundBlaster Pro selects register 020h for 030h, 022h for 032h, + 026h for 036h, and 028h for 038h. */ + case 0x30: + case 0x32: + case 0x36: + case 0x38: + mixer->regs[mixer->index - 0x10] = (val & 0xee); + break; + + case 0x00: + case 0x04: + case 0x0a: + case 0x0c: + case 0x0e: + case 0x2e: + break; + + /* Aztech AZTPR16 mixer */ + case 0x84: + case 0x86: + case 0x88: + case 0x8a: + case 0x8c: + case 0x8e: + case 0xa0: + case 0xa2: + case 0xa4: + case 0xa6: + case 0xa8: + case 0xaa: + case 0xac: + case 0xae: + case 0xc2: + case 0xc4: + case 0xc6: + case 0xc8: + case 0xca: + case 0xcc: + case 0xce: + case 0xe0: + case 0xe2: + case 0xe4: + case 0xe6: + case 0xe8: + break; + + default: + sb_log("sb_ct1345: Unknown register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + break; + } } else { mixer->regs[mixer->index] = val; @@ -967,6 +1038,36 @@ sb_ct1345_mixer_read(uint16_t addr, void *priv) case 0x38: return mixer->regs[mixer->index]; + /* Aztech AZTPR16 mixer */ + case 0x84: + case 0x86: + case 0x88: + case 0x8a: + case 0x8c: + case 0x8e: + case 0xa0: + case 0xa2: + case 0xa4: + case 0xa6: + case 0xa8: + case 0xaa: + case 0xac: + case 0xae: + case 0xc2: + case 0xc4: + case 0xc6: + case 0xc8: + case 0xca: + case 0xcc: + case 0xce: + case 0xe0: + case 0xe2: + case 0xe4: + case 0xe6: + case 0xe8: + if (sb->dsp.sb_subtype == SB_SUBTYPE_CLONE_AZTPR16_0X09) + return mixer->regs[mixer->index]; + default: sb_log("sb_ct1345: Unknown register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); break; diff --git a/src/sound/snd_sb_dsp.c b/src/sound/snd_sb_dsp.c index 89039580595..8adb46c5d85 100644 --- a/src/sound/snd_sb_dsp.c +++ b/src/sound/snd_sb_dsp.c @@ -1287,6 +1287,8 @@ sb_exec_command(sb_dsp_t *dsp) sb_add_data(dsp, 0x11); /* AZTECH get type, WASHINGTON/latest - according to devkit. E.g.: The one in the Itautec Infoway Multimidia */ else if ((dsp->sb_data[0] == 0x05 || dsp->sb_data[0] == 0x55) && dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C) sb_add_data(dsp, 0x0C); /* AZTECH get type, CLINTON - according to devkit. E.g.: The one in the Packard Bell Legend 100CD */ + else if ((dsp->sb_data[0] == 0x05 || dsp->sb_data[0] == 0x55) && dsp->sb_subtype == SB_SUBTYPE_CLONE_AZTPR16_0X09) + sb_add_data(dsp, 0x09); /* AZTECH get type, AZTPR16 */ else if (dsp->sb_data[0] == 0x08) { /* EEPROM address to write followed by byte */ if (dsp->sb_data[1] < 0 || dsp->sb_data[1] >= AZTECH_EEPROM_SIZE) @@ -1307,6 +1309,9 @@ sb_exec_command(sb_dsp_t *dsp) /* HACK: Aztech HWSET seems to rely on RP being incremented for detection to work after EMUTSR is run */ dsp->sb_read_rp++; break; + } else if ((dsp->sb_data[0] == 0x0f) && (dsp->sb_data[1] == 0xff) && (dsp->sb_subtype == SB_SUBTYPE_CLONE_AZTPR16_0X09)) { + sb_dsp_log("AZTPR16: Command 0x08, Subcommand 0x0f/0xff\n"); + sb_add_data(dsp, 0x80); } else sb_dsp_log("AZT2316A: UNKNOWN 0x08 COMMAND: %02X\n", dsp->sb_data[0]); /* 0x08 (when shutting down, driver tries to read 1 byte of response), 0x55, 0x0D, 0x08D seen */ break; @@ -1324,6 +1329,9 @@ sb_exec_command(sb_dsp_t *dsp) } else if (dsp->sb_data[0] == 0x01) { sb_dsp_log("AZT2316A: SB8PROV2 MODE!\n"); azt2316a_enable_wss(0, dsp->parent); + } else if ((dsp->sb_data[0] == 0x0f) && (dsp->sb_subtype == SB_SUBTYPE_CLONE_AZTPR16_0X09)) { + sb_dsp_log("AZTPR16: Mode switch command, params = %02X, %02X\n", dsp->sb_data[0], dsp->sb_data[1]); + aztpr16_wss_mode(dsp->sb_data[1], dsp->parent); } else sb_dsp_log("AZT2316A: UNKNOWN MODE! = %02x\n", dsp->sb_data[0]); // sequences 0x02->0xFF, 0x04->0xFF seen } @@ -1738,6 +1746,9 @@ sb_exec_command(sb_dsp_t *dsp) } else if (dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C) { sb_add_data(dsp, 0x2); sb_add_data(dsp, 0x1); + } else if (dsp->sb_subtype == SB_SUBTYPE_CLONE_AZTPR16_0X09) { + sb_add_data(dsp, 0x2); + sb_add_data(dsp, 0x1); } break; } @@ -1948,7 +1959,9 @@ sb_write(uint16_t addr, uint8_t val, void *priv) /* variable length commands */ if (dsp->sb_command == 0x08 && dsp->sb_data_stat == 1 && dsp->sb_data[0] == 0x08) sb_commands[dsp->sb_command] = 3; - else if (dsp->sb_command == 0x08 && dsp->sb_data_stat == 1 && dsp->sb_data[0] == 0x07) + else if (dsp->sb_command == 0x08 && dsp->sb_data_stat == 1 && (dsp->sb_data[0] == 0x07 || dsp->sb_data[0] == 0x0f)) + sb_commands[dsp->sb_command] = 2; + else if (dsp->sb_command == 0x09 && dsp->sb_data_stat == 1 && dsp->sb_data[0] == 0x0f) sb_commands[dsp->sb_command] = 2; } } @@ -1957,7 +1970,7 @@ sb_write(uint16_t addr, uint8_t val, void *priv) dsp->sb_data_stat = -1; if (IS_AZTECH(dsp)) { /* variable length commands */ - if (dsp->sb_command == 0x08) + if (dsp->sb_command == 0x08 || dsp->sb_command == 0x09) sb_commands[dsp->sb_command] = 1; } } @@ -2775,6 +2788,7 @@ pollsb(void *priv) dsp->ess_dma_counter += 4; break; case 0x30: /* Stereo signed */ + case 0x36: data[0] = dsp->dma_readw(dsp->dma_priv); data[1] = dsp->dma_readw(dsp->dma_priv); if ((data[0] == DMA_NODATA) || (data[1] == DMA_NODATA)) diff --git a/src/sound/snd_ymf701.c b/src/sound/snd_ymf701.c index 3b352932040..c6b1467c8bb 100644 --- a/src/sound/snd_ymf701.c +++ b/src/sound/snd_ymf701.c @@ -428,7 +428,7 @@ ymf701_init(const device_t *info) ymf701->sb->opl_mixer = ymf701; ymf701->sb->opl_mix = ymf701_filter_opl; - fm_driver_get(FM_YMF262, &ymf701->sb->opl); + fm_driver_get(FM_YMF289B, &ymf701->sb->opl); io_sethandler(ymf701->cur_sb_addr + 0, 0x0004, ymf701->sb->opl.read, NULL, NULL, ymf701->sb->opl.write, NULL, NULL, ymf701->sb->opl.priv); io_sethandler(ymf701->cur_sb_addr + 8, 0x0002, ymf701->sb->opl.read, NULL, NULL, ymf701->sb->opl.write, NULL, NULL, ymf701->sb->opl.priv); io_sethandler(0x0388, 0x0004, ymf701->sb->opl.read, NULL, NULL, ymf701->sb->opl.write, NULL, NULL, ymf701->sb->opl.priv); diff --git a/src/sound/snd_ymf71x.c b/src/sound/snd_ymf71x.c index c79263ce0ea..70ccf68726e 100644 --- a/src/sound/snd_ymf71x.c +++ b/src/sound/snd_ymf71x.c @@ -718,7 +718,7 @@ ymf71x_init(const device_t *info) ymf71x->sb->opl_mixer = ymf71x; ymf71x->sb->opl_mix = ymf71x_filter_opl; - fm_driver_get(FM_YMF262, &ymf71x->sb->opl); + fm_driver_get(FM_YMF289B, &ymf71x->sb->opl); sound_add_handler(ymf71x_get_buffer, ymf71x); music_add_handler(sb_get_music_buffer_sbpro, ymf71x->sb); diff --git a/src/sound/sndio.c b/src/sound/sndio.c index 6363163a218..3f8c90b897a 100644 --- a/src/sound/sndio.c +++ b/src/sound/sndio.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -30,11 +31,12 @@ #define I_CD 3 #define I_MIDI 4 #define I_FDD 5 +#define I_HDD 6 -static struct sio_hdl* audio[6] = {NULL, NULL, NULL, NULL, NULL, NULL}; -static struct sio_par info[6]; -static int freqs[6] = { SOUND_FREQ, MUSIC_FREQ, WT_FREQ, CD_FREQ, SOUND_FREQ, 0 }; - +extern bool fast_forward; +static struct sio_hdl* audio[7] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL}; +static struct sio_par info[7]; +static int freqs[7] = { SOUND_FREQ, MUSIC_FREQ, WT_FREQ, CD_FREQ, SOUND_FREQ, SOUND_FREQ, 0 }; void closeal(void) { @@ -83,7 +85,7 @@ givealbuffer_common(const void *buf, const uint8_t src, const int size) int conv_size; double gain; int target_rate; - if (audio[src] == NULL) + if (audio[src] == NULL || fast_forward) return; gain = sound_muted ? 0.0 : pow(10.0, (double) sound_gain / 20.0); @@ -153,6 +155,12 @@ givealbuffer_fdd(const void *buf, const uint32_t size) { givealbuffer_common(buf, I_FDD, (int) size); } + +void +givealbuffer_hdd(const void *buf, const uint32_t size) +{ + givealbuffer_common(buf, I_HDD, (int) size); +} void al_set_midi(const int freq, UNUSED(const int buf_size)) diff --git a/src/sound/sound.c b/src/sound/sound.c index 4b3575bc092..c7aefc746b2 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -37,6 +37,7 @@ #include <86box/snd_mpu401.h> #include <86box/sound.h> #include <86box/fdd_audio.h> +#include <86box/hdd_audio.h> typedef struct { const device_t *device; @@ -96,6 +97,12 @@ static event_t *sound_fdd_start_event; static volatile int fddaudioon = 0; static int fdd_thread_enable = 0; +static thread_t *sound_hdd_thread_h; +static event_t *sound_hdd_event; +static event_t *sound_hdd_start_event; +static volatile int hddaudioon = 0; +static int hdd_thread_enable = 0; + static void (*filter_cd_audio)(int channel, double *buffer, void *priv) = NULL; static void *filter_cd_audio_p = NULL; @@ -116,12 +123,10 @@ static const SOUND_CARD sound_cards[] = { { &ess_ess0968_pnp_device }, { &ssi2001_device }, { &mmb_device }, +#ifdef USE_LIBSERIALPORT /*The following devices required LIBSERIALPORT*/ + { &opl2board_device }, +#endif { &pasplus_device }, - { &voicemasterkey_device }, - { &soundmasterplus_device }, - { &soundman_device }, - { &isadacr0_device }, - { &isadacr1_device }, { &sb_1_device }, { &sb_15_device }, { &sb_2_device }, @@ -130,15 +135,19 @@ static const SOUND_CARD sound_cards[] = { { &entertainer_device }, { &pssj_isa_device }, { &tndy_device }, -#ifdef USE_LIBSERIALPORT /*The following devices required LIBSERIALPORT*/ - { &opl2board_device }, -#endif /* ISA/Sidecar */ { &adlib_device }, + { &soundmasterplus_device }, + { &voicemasterkey_device }, + { &isadacr0_device }, + { &isadacr1_device }, + { &soundman_device }, /* ISA16 */ { &acermagic_s20_device }, + { &ad1816_device }, { &azt2316a_device }, { &azt1605_device }, + { &aztpr16_device }, { &sb_goldfinch_device }, { &cs4232_device }, { &cs4235_device }, @@ -613,6 +622,10 @@ sound_poll(UNUSED(void *priv)) if (fdd_thread_enable) { thread_set_event(sound_fdd_event); } + + if (hdd_thread_enable) { + thread_set_event(sound_hdd_event); + } sound_pos_global = 0; } } @@ -856,3 +869,59 @@ sound_fdd_thread_end(void) } } } + +static void +sound_hdd_thread(UNUSED(void *param)) +{ + thread_set_event(sound_hdd_start_event); + while (hddaudioon) { + thread_wait_event(sound_hdd_event, -1); + thread_reset_event(sound_hdd_event); + + if (!hddaudioon) + break; + + static float hdd_float_buffer[SOUNDBUFLEN * 2]; + memset(hdd_float_buffer, 0, sizeof(hdd_float_buffer)); + hdd_audio_callback((int16_t*)hdd_float_buffer, SOUNDBUFLEN * 2); + givealbuffer_hdd(hdd_float_buffer, SOUNDBUFLEN * 2); + } +} + +void +sound_hdd_thread_init(void) +{ + if (!hddaudioon) { + hddaudioon = 1; + hdd_thread_enable = 1; + sound_hdd_start_event = thread_create_event(); + sound_hdd_event = thread_create_event(); + sound_hdd_thread_h = thread_create(sound_hdd_thread, NULL); + + thread_wait_event(sound_hdd_start_event, -1); + thread_reset_event(sound_hdd_start_event); + } +} + +void +sound_hdd_thread_end(void) +{ + if (hddaudioon) { + hddaudioon = 0; + hdd_thread_enable = 0; + thread_set_event(sound_hdd_event); + thread_wait(sound_hdd_thread_h); + + if (sound_hdd_event) { + thread_destroy_event(sound_hdd_event); + sound_hdd_event = NULL; + } + + sound_hdd_thread_h = NULL; + if (sound_hdd_start_event) { + thread_destroy_event(sound_hdd_start_event); + sound_hdd_start_event = NULL; + } + } +} + diff --git a/src/sound/sound_util.c b/src/sound/sound_util.c new file mode 100644 index 00000000000..d6d3e74953f --- /dev/null +++ b/src/sound/sound_util.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include + +#include <86box/86box.h> +#include <86box/mem.h> +#include <86box/rom.h> +#include <86box/plat.h> +#include <86box/sound_util.h> + +int16_t * +sound_load_wav(const char *filename, int *sample_count) +{ + if ((filename == NULL) || (strlen(filename) == 0)) + return NULL; + + if (strstr(filename, "..") != NULL) + return NULL; + + FILE *f = asset_fopen(filename, "rb"); + if (f == NULL) + return NULL; + + wav_header_t hdr; + if (fread(&hdr, sizeof(hdr), 1, f) != 1) { + fclose(f); + return NULL; + } + + if (memcmp(hdr.riff, "RIFF", 4) || memcmp(hdr.wave, "WAVE", 4) || + memcmp(hdr.fmt, "fmt ", 4) || memcmp(hdr.data, "data", 4)) { + fclose(f); + return NULL; + } + + /* Accept both mono and stereo, 16-bit PCM */ + if (hdr.audio_format != 1 || hdr.bits_per_sample != 16 || + (hdr.num_channels != 1 && hdr.num_channels != 2)) { + fclose(f); + return NULL; + } + + int input_samples = hdr.data_size / 2; + int16_t *input_data = malloc(hdr.data_size); + if (!input_data) { + fclose(f); + return NULL; + } + + if (fread(input_data, 1, hdr.data_size, f) != hdr.data_size) { + free(input_data); + fclose(f); + return NULL; + } + fclose(f); + + int16_t *output_data; + int output_samples; + + if (hdr.num_channels == 1) { + /* Convert mono to stereo */ + output_samples = input_samples; + output_data = malloc(input_samples * 2 * sizeof(int16_t)); + if (!output_data) { + free(input_data); + return NULL; + } + + for (int i = 0; i < input_samples; i++) { + output_data[i * 2] = input_data[i]; + output_data[i * 2 + 1] = input_data[i]; + } + + free(input_data); + } else { + output_data = input_data; + output_samples = input_samples / 2; + } + + if (sample_count) + *sample_count = output_samples; + + return output_data; +} \ No newline at end of file diff --git a/src/sound/xaudio2.c b/src/sound/xaudio2.c index 8596c2a4943..4d109bce9ec 100644 --- a/src/sound/xaudio2.c +++ b/src/sound/xaudio2.c @@ -14,6 +14,7 @@ */ #include #include +#include #include #include #include @@ -54,6 +55,9 @@ static IXAudio2SourceVoice *srcvoicewt = NULL; static IXAudio2SourceVoice *srcvoicemidi = NULL; static IXAudio2SourceVoice *srcvoicecd = NULL; static IXAudio2SourceVoice *srcvoicefdd = NULL; +static IXAudio2SourceVoice *srcvoicehdd = NULL; + +extern bool fast_forward; #define FREQ SOUND_FREQ #define BUFLEN SOUNDBUFLEN @@ -184,6 +188,7 @@ inital(void) fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign; (void) IXAudio2_CreateSourceVoice(xaudio2, &srcvoicefdd, &fmt, 0, 2.0f, &callbacks, NULL, NULL); + (void) IXAudio2_CreateSourceVoice(xaudio2, &srcvoicehdd, &fmt, 0, 2.0f, &callbacks, NULL, NULL); (void) IXAudio2SourceVoice_SetVolume(srcvoice, 1, XAUDIO2_COMMIT_NOW); (void) IXAudio2SourceVoice_Start(srcvoice, 0, XAUDIO2_COMMIT_NOW); @@ -191,6 +196,7 @@ inital(void) (void) IXAudio2SourceVoice_Start(srcvoicemusic, 0, XAUDIO2_COMMIT_NOW); (void) IXAudio2SourceVoice_Start(srcvoicewt, 0, XAUDIO2_COMMIT_NOW); (void) IXAudio2SourceVoice_Start(srcvoicefdd, 0, XAUDIO2_COMMIT_NOW); + (void) IXAudio2SourceVoice_Start(srcvoicehdd, 0, XAUDIO2_COMMIT_NOW); const char *mdn = midi_out_device_get_internal_name(midi_output_device_current); @@ -223,6 +229,8 @@ closeal(void) (void) IXAudio2SourceVoice_FlushSourceBuffers(srcvoicecd); (void) IXAudio2SourceVoice_Stop(srcvoicefdd, 0, XAUDIO2_COMMIT_NOW); (void) IXAudio2SourceVoice_FlushSourceBuffers(srcvoicefdd); + (void) IXAudio2SourceVoice_Stop(srcvoicehdd, 0, XAUDIO2_COMMIT_NOW); + (void) IXAudio2SourceVoice_FlushSourceBuffers(srcvoicehdd); if (srcvoicemidi) { (void) IXAudio2SourceVoice_Stop(srcvoicemidi, 0, XAUDIO2_COMMIT_NOW); (void) IXAudio2SourceVoice_FlushSourceBuffers(srcvoicemidi); @@ -231,6 +239,7 @@ closeal(void) IXAudio2SourceVoice_DestroyVoice(srcvoicewt); IXAudio2SourceVoice_DestroyVoice(srcvoicecd); IXAudio2SourceVoice_DestroyVoice(srcvoicefdd); + IXAudio2SourceVoice_DestroyVoice(srcvoicehdd); IXAudio2SourceVoice_DestroyVoice(srcvoicemusic); IXAudio2SourceVoice_DestroyVoice(srcvoice); IXAudio2MasteringVoice_DestroyVoice(mastervoice); @@ -239,6 +248,7 @@ closeal(void) srcvoicecd = NULL; srcvoicemidi = NULL; srcvoicefdd = NULL; + srcvoicehdd = NULL; mastervoice = NULL; xaudio2 = NULL; @@ -251,7 +261,7 @@ closeal(void) void givealbuffer_common(const void *buf, IXAudio2SourceVoice *sourcevoice, const size_t buflen) { - if (!initialized) + if (!initialized || fast_forward) return; (void) IXAudio2MasteringVoice_SetVolume(mastervoice, sound_muted ? 0.0 : pow(10.0, (double) sound_gain / 20.0), @@ -312,6 +322,18 @@ givealbuffer_fdd(const void *buf, const uint32_t size) givealbuffer_common(buf, srcvoicefdd, size); } +void +givealbuffer_hdd(const void *buf, const uint32_t size) +{ + if (!initialized) + return; + + if (!srcvoicefdd) + return; + + givealbuffer_common(buf, srcvoicehdd, size); +} + void al_set_midi(const int freq, const int buf_size) { diff --git a/src/timer.c b/src/timer.c index 03908890f8d..34c1e74f5ca 100644 --- a/src/timer.c +++ b/src/timer.c @@ -8,7 +8,7 @@ #include <86box/nv/vid_nv_rivatimer.h> uint64_t TIMER_USEC; -uint32_t timer_target; +uint64_t timer_target; /*Enabled timers are stored in a linked list, with the first timer to expire at the head.*/ @@ -23,68 +23,55 @@ void timer_enable(pc_timer_t *timer) { pc_timer_t *timer_node = timer_head; - int ret = 0; - - if (!timer_inited || (timer == NULL)) - return; if (timer->flags & TIMER_ENABLED) timer_disable(timer); if (timer->next || timer->prev) - fatal("timer_disable(): Attempting to enable a non-isolated " - "timer incorrectly marked as disabled\n"); + fatal("timer_enable - timer->next\n"); + + timer->flags |= TIMER_ENABLED; /*List currently empty - add to head*/ if (!timer_head) { - timer_head = timer; + timer_head = timer; timer->next = timer->prev = NULL; - timer_target = timer_head->ts.ts32.integer; - ret = 1; - } else if (TIMER_LESS_THAN(timer, timer_head)) { - timer->next = timer_head; - timer->prev = NULL; - timer_head->prev = timer; - timer_head = timer; - timer_target = timer_head->ts.ts32.integer; - ret = 1; - } else if (!timer_head->next) { - timer_head->next = timer; - timer->prev = timer_head; - ret = 1; + timer_target = timer_head->ts_integer; + return; } - if (ret == 0) { - pc_timer_t *prev = timer_head; - timer_node = timer_head->next; - - while (1) { - /*Timer expires before timer_node. Add to list in front of timer_node*/ - if (TIMER_LESS_THAN(timer, timer_node)) { - timer->next = timer_node; - timer->prev = prev; - timer_node->prev = timer; - prev->next = timer; - ret = 1; - break; - } + timer_node = timer_head; - /*timer_node is last in the list. Add timer to end of list*/ - if (!timer_node->next) { - timer_node->next = timer; - timer->prev = timer_node; - ret = 1; - break; + while (1) { + /* + Timer expires before timer_node. + Add to list in front of timer_node + */ + if (TIMER_LESS_THAN(timer, timer_node)) { + timer->next = timer_node; + timer->prev = timer_node->prev; + timer_node->prev = timer; + if (timer->prev) + timer->prev->next = timer; + else { + timer_head = timer; + timer_target = timer_head->ts_integer; } + return; + } - prev = timer_node; - timer_node = timer_node->next; + /* + timer_node is last in the list. + Add timer to end of list + */ + if (!timer_node->next) { + timer_node->next = timer; + timer->prev = timer_node; + return; } - } - /* Do not mark it as enabled if it has failed every single condition. */ - if (ret == 1) - timer->flags |= TIMER_ENABLED; + timer_node = timer_node->next; + } } void @@ -93,9 +80,12 @@ timer_disable(pc_timer_t *timer) if (!timer_inited || (timer == NULL) || !(timer->flags & TIMER_ENABLED)) return; - if (!timer->next && !timer->prev && timer != timer_head) + if (!timer->next && !timer->prev && timer != timer_head) { + uint32_t *p = NULL; + *p = 5; /* Crash deliberately. */ fatal("timer_disable(): Attempting to disable an isolated " "non-head timer incorrectly marked as enabled\n"); + } timer->flags &= ~TIMER_ENABLED; timer->in_callback = 0; @@ -109,41 +99,52 @@ timer_disable(pc_timer_t *timer) timer->prev = timer->next = NULL; } +static void +timer_remove_head(void) +{ + if (timer_head) { + pc_timer_t *timer = timer_head; + timer_head = timer->next; + timer_head->prev = NULL; + timer->next = timer->prev = NULL; + timer->flags &= ~TIMER_ENABLED; + } +} + void timer_process(void) { - pc_timer_t *timer; + int num = 0; if (!timer_head) return; while (1) { - timer = timer_head; + pc_timer_t *timer = timer_head; - if (!TIMER_LESS_THAN_VAL(timer, (uint32_t) tsc)) + if (!TIMER_LESS_THAN_VAL(timer, (uint64_t) tsc)) break; - timer_head = timer->next; - if (timer_head) - timer_head->prev = NULL; - - timer->next = timer->prev = NULL; - timer->flags &= ~TIMER_ENABLED; + timer_remove_head(); if (timer->flags & TIMER_SPLIT) timer_advance_ex(timer, 0); /* We're splitting a > 1 s period into - multiple <= 1 s periods. */ + multiple <= 1 s periods. */ else if (timer->callback != NULL) { - /* Make sure it's not NULL, so that we can + /* + Make sure it's not NULL, so that we can have a NULL callback when no operation - is needed. */ + is needed. + */ timer->in_callback = 1; timer->callback(timer->priv); timer->in_callback = 0; } + + num++; } - timer_target = timer_head->ts.ts32.integer; + timer_target = timer_head->ts_integer; } void @@ -200,7 +201,8 @@ timer_stop(pc_timer_t *timer) return; timer->period = 0.0; - timer_disable(timer); + if (timer->flags & TIMER_ENABLED) + timer_disable(timer); timer->flags &= ~TIMER_SPLIT; timer->in_callback = 0; } @@ -277,11 +279,11 @@ timer_set_new_tsc(uint64_t new_tsc) } timer = timer_head; - timer_target = new_tsc + (int32_t)(timer_get_ts_int(timer_head) - (uint32_t)tsc); + timer_target = new_tsc + (int64_t)(timer_get_ts_int(timer_head) - (uint64_t)tsc); while (timer) { - int32_t offset_from_current_tsc = (int32_t)(timer_get_ts_int(timer) - (uint32_t)tsc); - timer->ts.ts32.integer = new_tsc + offset_from_current_tsc; + int64_t offset_from_current_tsc = (int64_t)(timer_get_ts_int(timer) - (uint64_t)tsc); + timer->ts_integer = new_tsc + offset_from_current_tsc; timer = timer->next; } diff --git a/src/unix/CMakeLists.txt b/src/unix/CMakeLists.txt index 1d428fa2b41..1c79b42d2e8 100644 --- a/src/unix/CMakeLists.txt +++ b/src/unix/CMakeLists.txt @@ -22,6 +22,7 @@ add_library(plat OBJECT unix.c unix_serial_passthrough.c unix_netsocket.c + ../qt/sdl_joystick.c ) if (NOT CPPTHREADS) diff --git a/src/unix/assets/86Box.spec b/src/unix/assets/86Box.spec index 35916ffff1c..a189a5f41ae 100644 --- a/src/unix/assets/86Box.spec +++ b/src/unix/assets/86Box.spec @@ -12,10 +12,10 @@ # After a successful build, you can install the RPMs as follows: # sudo dnf install RPMS/$(uname -m)/86Box-3* RPMS/noarch/86Box-roms* -%global romver 5.2 +%global romver 5.4 Name: 86Box -Version: 6.0 +Version: 5.4 Release: 1%{?dist} Summary: Classic PC emulator License: GPLv2+ @@ -121,5 +121,5 @@ popd %{_datadir}/%{name}/roms %changelog -* Sat Aug 31 Jasmine Iwanek 6.0-1 +* Sat Aug 31 Jasmine Iwanek 5.4-1 - Bump release diff --git a/src/unix/assets/net.86box.86Box.metainfo.xml b/src/unix/assets/net.86box.86Box.metainfo.xml index 1e929412c24..c6a612a4c15 100644 --- a/src/unix/assets/net.86box.86Box.metainfo.xml +++ b/src/unix/assets/net.86box.86Box.metainfo.xml @@ -11,7 +11,7 @@ net.86box.86Box.desktop - + diff --git a/src/unix/dummy_cdrom_ioctl.c b/src/unix/dummy_cdrom_ioctl.c index af8679ecc66..9b7a8bfbfb5 100644 --- a/src/unix/dummy_cdrom_ioctl.c +++ b/src/unix/dummy_cdrom_ioctl.c @@ -24,6 +24,7 @@ #include #include #define HAVE_STDARG_H +#include <86box/86box.h> #include <86box/scsi_device.h> #include <86box/cdrom.h> #include <86box/log.h> diff --git a/src/unix/unix.c b/src/unix/unix.c index ce644cac686..50b7f0f98d0 100644 --- a/src/unix/unix.c +++ b/src/unix/unix.c @@ -63,13 +63,11 @@ int update_icons; int kbd_req_capture; int hide_status_bar; int hide_tool_bar; +bool fast_forward = false; int fixed_size_x = 640; int fixed_size_y = 480; extern int title_set; extern wchar_t sdl_win_title[512]; -plat_joystick_state_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; -joystick_state_t joystick_state[GAMEPORT_MAX][MAX_JOYSTICKS]; -int joysticks_present; SDL_mutex *blitmtx; SDL_threadID eventthread; static int exit_event = 0; @@ -599,10 +597,10 @@ main_thread(UNUSED(void *param)) #endif old_time = new_time; - if (drawits > 0 && !dopause) { + if ((drawits > 0 || fast_forward) && !dopause) { /* Yes, so do one frame now. */ drawits -= force_10ms ? 10 : 1; - if (drawits > 50) + if (drawits > 50 || fast_forward) drawits = 0; /* Run a block of code. */ @@ -691,9 +689,9 @@ ui_msgbox_header(int flags, void *header, void *message) if (!header) { if (flags & MBX_ANSI) - header = (void *) "86Box"; + header = (void *) EMU_NAME; else - header = (void *) L"86Box"; + header = (void *) EMU_NAME_W; } msgbtn.buttonid = 1; @@ -736,7 +734,7 @@ plat_get_exe_name(char *s, int size) { char *basepath = SDL_GetBasePath(); - snprintf(s, size, "%s%s", basepath, basepath[strlen(basepath) - 1] == '/' ? "86box" : "/86box"); + snprintf(s, size, "%s%s", basepath, basepath[strlen(basepath) - 1] == '/' ? EMU_NAME : "/" EMU_NAME); } void @@ -830,7 +828,7 @@ plat_init_rom_paths(void) char xdg_rom_path[TMP_PATH_BUFSIZE] = {0}; size_t used = snprintf(xdg_rom_path, sizeof(xdg_rom_path), "%s/", xdg_data_home); if (used < sizeof(xdg_rom_path)) - used += snprintf(xdg_rom_path + used, sizeof(xdg_rom_path) - used, "86Box/"); + used += snprintf(xdg_rom_path + used, sizeof(xdg_rom_path) - used, EMU_NAME "/"); if (used < sizeof(xdg_rom_path) && !plat_dir_check(xdg_rom_path)) plat_dir_create(xdg_rom_path); if (used < sizeof(xdg_rom_path)) @@ -850,7 +848,7 @@ plat_init_rom_paths(void) if (home) { char home_rom_path[TMP_PATH_BUFSIZE] = {0}; size_t used = snprintf(home_rom_path, sizeof(home_rom_path), - "%s/.local/share/86Box/", home); + "%s/.local/share/" EMU_NAME "/", home); if (used < sizeof(home_rom_path) && !plat_dir_check(home_rom_path)) plat_dir_create(home_rom_path); if (used < sizeof(home_rom_path)) @@ -878,7 +876,7 @@ plat_init_rom_paths(void) char real_xdg_rom_path[TMP_PATH_BUFSIZE] = {0}; size_t used = snprintf(real_xdg_rom_path, sizeof(real_xdg_rom_path), - "%s/86Box/roms/", cur_xdg); + "%s/" EMU_NAME "/roms/", cur_xdg); if (used < sizeof(real_xdg_rom_path)) rom_add_path(real_xdg_rom_path); cur_xdg = strtok_r(NULL, ":", &saveptr); @@ -887,8 +885,8 @@ plat_init_rom_paths(void) free(xdg_rom_paths); } } else { - rom_add_path("/usr/local/share/86Box/roms/"); - rom_add_path("/usr/share/86Box/roms/"); + rom_add_path("/usr/local/share/" EMU_NAME "/roms/"); + rom_add_path("/usr/share/" EMU_NAME "/roms/"); } #else char default_rom_path[TMP_PATH_BUFSIZE] = {0}; @@ -906,7 +904,7 @@ plat_init_asset_paths(void) char xdg_asset_path[TMP_PATH_BUFSIZE] = {0}; size_t used = snprintf(xdg_asset_path, sizeof(xdg_asset_path), "%s/", xdg_data_home); if (used < sizeof(xdg_asset_path)) - used += snprintf(xdg_asset_path + used, sizeof(xdg_asset_path) - used, "86Box/"); + used += snprintf(xdg_asset_path + used, sizeof(xdg_asset_path) - used, EMU_NAME "/"); if (used < sizeof(xdg_asset_path) && !plat_dir_check(xdg_asset_path)) plat_dir_create(xdg_asset_path); if (used < sizeof(xdg_asset_path)) @@ -926,7 +924,7 @@ plat_init_asset_paths(void) if (home) { char home_asset_path[TMP_PATH_BUFSIZE] = {0}; size_t used = snprintf(home_asset_path, sizeof(home_asset_path), - "%s/.local/share/86Box/", home); + "%s/.local/share/" EMU_NAME "/", home); if (used < sizeof(home_asset_path) && !plat_dir_check(home_asset_path)) plat_dir_create(home_asset_path); if (used < sizeof(home_asset_path)) @@ -954,7 +952,7 @@ plat_init_asset_paths(void) char real_xdg_asset_path[TMP_PATH_BUFSIZE] = {0}; size_t used = snprintf(real_xdg_asset_path, sizeof(real_xdg_asset_path), - "%s/86Box/assets/", cur_xdg); + "%s/" EMU_NAME "/assets/", cur_xdg); if (used < sizeof(real_xdg_asset_path)) asset_add_path(real_xdg_asset_path); cur_xdg = strtok_r(NULL, ":", &saveptr); @@ -963,8 +961,8 @@ plat_init_asset_paths(void) free(xdg_asset_paths); } } else { - asset_add_path("/usr/local/share/86Box/assets/"); - asset_add_path("/usr/share/86Box/assets/"); + asset_add_path("/usr/local/share/" EMU_NAME "/assets/"); + asset_add_path("/usr/share/" EMU_NAME "/assets/"); } #else char default_asset_path[TMP_PATH_BUFSIZE] = {0}; @@ -986,7 +984,7 @@ plat_get_global_data_dir(char *outbuf, const size_t len) if (portable_mode) { strncpy(outbuf, exe_path, len); } else { - char *prefPath = SDL_GetPrefPath(NULL, "86Box"); + char *prefPath = SDL_GetPrefPath(NULL, EMU_NAME); strncpy(outbuf, prefPath, len); SDL_free(prefPath); } @@ -1107,9 +1105,11 @@ unix_executeLine(char *line) "moeject - eject image from MO drive .\n\n" "hardreset - hard reset the emulated system.\n" "pause - pause the the emulated system.\n" + "fastfwd - toggle fast forward.\n" + "screenshot - save a screenshot.\n" "fullscreen - toggle fullscreen.\n" "version - print version and license information.\n" - "exit - exit 86Box.\n"); + "exit - exit " EMU_NAME ".\n"); } else if (strncasecmp(xargv[0], "exit", 4) == 0) { exit_event = 1; } else if (strncasecmp(xargv[0], "version", 7) == 0) { @@ -1147,9 +1147,17 @@ unix_executeLine(char *line) } else if (strncasecmp(xargv[0], "fullscreen", 10) == 0) { video_fullscreen = video_fullscreen ? 0 : 1; fullscreen_pending = 1; + } else if (strncasecmp(xargv[0], "screenshot", 10) == 0) { + startblit(); + ++monitors[0].mon_screenshots_raw; + endblit(); + device_force_redraw(); } else if (strncasecmp(xargv[0], "pause", 5) == 0) { plat_pause(dopause ^ 1); printf("%s", dopause ? "Paused.\n" : "Unpaused.\n"); + } else if (strncasecmp(xargv[0], "fastfwd", 7) == 0) { + fast_forward ^= 1; + printf("%s", fast_forward ? "Fast forward on.\n" : "Fast forward off.\n"); } else if (strncasecmp(xargv[0], "hardreset", 9) == 0) { pc_reset_hard(); } else if (strncasecmp(xargv[0], "cdload", 6) == 0 && cmdargc >= 3) { @@ -1299,7 +1307,7 @@ monitor_thread(UNUSED(void *param)) char *line = NULL; size_t n; - printf("86Box monitor console.\n"); + printf(EMU_NAME " monitor console.\n"); while (!exit_event) { if (feof(stdin)) @@ -1307,10 +1315,10 @@ monitor_thread(UNUSED(void *param)) #ifdef ENABLE_READLINE if (f_readline) - line = f_readline("(86Box) "); + line = f_readline("(" EMU_NAME ") "); else { #endif - printf("(86Box) "); + printf("(" EMU_NAME ") "); (void) !getline(&line, &n, stdin); #ifdef ENABLE_READLINE } @@ -1338,7 +1346,7 @@ main(int argc, char **argv) if (ret == 0) return 0; if (!pc_init_roms()) { - ui_msgbox_header(MBX_FATAL, L"No ROMs found.", L"86Box could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory."); + ui_msgbox_header(MBX_FATAL, L"No ROMs found.", EMU_NAME_W L" could not find any usable ROM images.\n\nPlease download a ROM set and extract it into the \"roms\" directory."); SDL_Quit(); return 6; } @@ -1689,24 +1697,6 @@ plat_language_code_r(UNUSED(int id), UNUSED(char *outbuf), UNUSED(int len)) return; } -void -joystick_init(void) -{ - /* No-op. */ -} - -void -joystick_close(void) -{ - /* No-op. */ -} - -void -joystick_process(uint8_t gp) -{ - /* No-op. */ -} - void startblit(void) { @@ -1731,3 +1721,9 @@ ui_hard_reset_completed(void) { /* No-op. */ } + +void +ui_update_force_interpreter(void) +{ + /* No-op. */ +} diff --git a/src/unix/unix_sdl.c b/src/unix/unix_sdl.c index 8d3a71002c5..fdd31d901ac 100644 --- a/src/unix/unix_sdl.c +++ b/src/unix/unix_sdl.c @@ -156,7 +156,7 @@ sdl_blit_shim(int x, int y, int w, int h, int monitor_index) for (int row = 0; row < h; ++row) video_copy(&(((uint8_t *) pixeldata)[row * 2048 * sizeof(uint32_t)]), &(buffer32->line[y + row][x]), w * sizeof(uint32_t)); - if (monitors[monitor_index].mon_screenshots) + if (monitors[monitor_index].mon_screenshots_raw) video_screenshot((uint32_t *) pixeldata, 0, 0, 2048); blitreq = 1; diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index bcbc7aafd5d..27be335afed 100644 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -16,6 +16,8 @@ # add_library(utils OBJECT + + # Core cJSON.c crc.c crc32.c @@ -24,4 +26,12 @@ add_library(utils OBJECT ini.c log.c random.c + +) + +add_library(mdsx_dll OBJECT + + # MDSX DLL Core + mdsx_dll.c + ) diff --git a/src/utils/defines.h b/src/utils/defines.h new file mode 100644 index 00000000000..fb8f5c79cd1 --- /dev/null +++ b/src/utils/defines.h @@ -0,0 +1,13 @@ +#ifndef DEFINES_H +#define DEFINES_H + +#include + +typedef uint64_t u64; +typedef int64_t s64; +typedef uint32_t u32; +typedef int32_t s32; +typedef uint8_t u8; +typedef int BOOL; + +#endif diff --git a/src/utils/mds.h b/src/utils/mds.h new file mode 100644 index 00000000000..eb1a0beb77f --- /dev/null +++ b/src/utils/mds.h @@ -0,0 +1,284 @@ +#ifndef MDS_H +#define MDS_H + +#include +#include +#include + +#include "defines.h" +// #include "common/crypto.h" + +#if defined( AES_VAR ) || defined( AES_256 ) +#define KS_LENGTH 60 +#elif defined( AES_192 ) +#define KS_LENGTH 52 +#else +#define KS_LENGTH 44 +#endif + +#define AES_RETURN int +#define TC_LARGEST_COMPILER_UINT uint64_t + +#define u16 uint16_t + +typedef union +{ + uint32_t l; + uint8_t b[4]; +} aes_inf; + +typedef struct +{ + uint32_t ks[KS_LENGTH]; + aes_inf inf; +} aes_encrypt_ctx; + +typedef struct +{ + uint32_t ks[KS_LENGTH]; + aes_inf inf; +} aes_decrypt_ctx; + +#ifndef u4byte +#define u4byte uint32_t +#endif + +typedef struct +{ + u4byte l_key[40]; + u4byte s_key[4]; +#if !defined (TC_MINIMIZE_CODE_SIZE) || defined (TC_WINDOWS_BOOT_TWOFISH) + u4byte mk_tab[4 * 256]; +#endif + u4byte k_len; +} TwofishInstance; + +#define AES_KS (sizeof(aes_encrypt_ctx) + sizeof(aes_decrypt_ctx)) +#define SERPENT_KS (140 * 4) +#define TWOFISH_KS sizeof(TwofishInstance) +#define MAX_EXPANDED_KEY (AES_KS + SERPENT_KS + TWOFISH_KS) +#define MASTER_KEYDATA_SIZE 256 +#define PKCS5_SALT_SIZE 64 +/* Encryption block length */ +#define CBLK_LEN 16 +#define CBLK_LEN8 8 + +typedef struct +{ + /* Union not used to support faster mounting */ + uint32_t gf_t128[CBLK_LEN * 2 / 2][16][CBLK_LEN / 4]; + uint32_t gf_t64[CBLK_LEN8 * 2][16][CBLK_LEN8 / 4]; +} GfCtx; + +typedef struct CRYPTO_INFO_t +{ + int ea; + int mode; + uint8_t ks[MAX_EXPANDED_KEY]; + uint8_t ks2[MAX_EXPANDED_KEY]; + + GfCtx gf_ctx; + + uint8_t master_keydata[MASTER_KEYDATA_SIZE]; + uint8_t k2[MASTER_KEYDATA_SIZE]; + uint8_t salt[PKCS5_SALT_SIZE]; + int noIterations; + int pkcs5; +} CRYPTO_INFO, *PCRYPTO_INFO; + +typedef struct Decoder_t +{ + u8 dg[32]; + GfCtx gf_ctx; + aes_encrypt_ctx encr; + aes_decrypt_ctx decr; + u8 bsize; + + int mode; + int ctr; +} Decoder; + + + +enum TRACK_TYPE +{ + TRK_T_MAINTENANCE = 0, + TRK_T_AUDIO = 1, + TRK_T_MODE1 = 2, + TRK_T_MODE2 = 3, + TRK_T_MODE2_FORM1 = 4, + TRK_T_MODE2_FORM2 = 5 +}; + +enum TRACK_FLAG +{ + TRK_F_TYPE_MASK = 7, + TRK_F_EDC = 8, + TRK_F_10 = 0x10, + TRK_F_HEADER = 0x20, + TRK_F_SUBHEADER = 0x40, + TRK_F_SYNC = 0x80 +}; + + +typedef struct __attribute__((packed)) +{ + u32 f0; + u32 f1; + u64 f3; //or two u32? +} UNK4; + +typedef struct __attribute__((packed)) +{ + char signature[16]; + u8 major; // 0x10 + u8 minor; + u16 medium_type; // 0x12 + u16 num_sessions; // 0x14 + u16 _unk1_; + u16 _unk2_size_; // 0x18 + u16 bca_len; + u16 _unk3_size_; // 0x1c + u16 _unk4_size_; // 0x1e + u32 _unk2_offset_; // 0x20 + u32 bca_data_offset; // 0x24 + u32 _unk3_offset_; // 0x28 + u32 _unk4_offset_; // 0x2c 0x10 byte elements UNK4 + u8 _unk5_; // 0x30 + u32 _unk6_; // 0x31 + u8 _unk7_; // 0x35 + u64 _unk8_; // 0x36 + u16 _unk9_; // 0x3e + u32 disc_structures_offset; // 0x40 + u32 _unk10_offset_; // 0x44 + u16 _unk10_size_; // 0x48 + u8 _dummy1_[6]; // 0x4a not used by DT + u32 sessions_blocks_offset; // 0x50 + u32 dpm_blocks_offset; // 0x54 + u32 encryption_block_offset; // 0x58 + u8 _dummy2_[4]; // 0x5c +} MDX_Header; // 0x60 + +typedef struct __attribute__((packed)) +{ + u64 session_start; + u16 session_number; // 0x8 + u8 num_all_blocks; // 0xa + u8 num_nontrack_blocks; // 0xb + u16 first_track; // 0xc + u16 last_track; // 0xe + u32 _dummy_; // 0x10 + u32 tracks_blocks_offset; // 0x14 + u64 session_end; // 0x18 +} MDX_SessionBlock; // 0x20 + +typedef struct __attribute__((packed)) +{ + u8 mode; + u8 subchannel; + u8 adr_ctl; + u8 tno; + u8 point; // 4 + u8 min; + u8 sec; + u8 frame; + u8 zero; // 8 + u8 pmin; + u8 psec; + u8 pframe; + u32 extra_offset; // 0xc + u16 file_block_size; // 0x10 original name. represent full size of data and additional data per sector + u8 _unk1_; // 0x12 + u8 _dummy1_[5]; // 0x13 + u32 _unk2_; // 0x18; + u32 _unk3_; // 0x1c; + u32 _unk4_; // 0x20; + u32 start_sector; // 0x24 + u64 start_offset; // 0x28 + u32 footer_count; // 0x30 + u32 footer_offset; // 0x34 + u64 start_sector64; // 0x38 major >= 2 + u64 track_size64; // 0x40 major >= 2 + u8 _dummy2_[8]; // 0x48 +} MDX_TrackBlock; // 0x50 + +typedef struct __attribute__((packed)) +{ + u32 filename_offset; + u8 flags; // 4 + u8 _dummy1_; // 5 + u16 _unk1_size_; // 6 + u32 _unk2_size_; // 8 + u32 blocks_in_compression_group; // c major >= 2 + u64 track_data_length; // 10 major >= 2 + u64 compress_table_offset; // 18 +} MDX_Footer; // 0x20 + + + + +// decode.c +#if 0 +void DecryptBlock(u8 *buf, TC_LARGEST_COMPILER_UINT len, u32 secSz, u64 secN, u8 flags, PCRYPTO_INFO cryptoInfo); + +int decode1(u8 *data, const char *pass, PCRYPTO_INFO *ci); + +void decryptMdxData(Decoder *ctx, u8 *buffer, u32 length, u64 blockSize, u64 blockIndex); +#else +#ifdef _WIN32 +# define MDSXDLLAPI __stdcall +#else +# define MDSXDLLAPI +#endif + +extern void(MDSXDLLAPI *DecryptBlock)(u8 *buf, TC_LARGEST_COMPILER_UINT len, u32 secSz, u64 secN, u8 flags, PCRYPTO_INFO cryptoInfo); +extern int(MDSXDLLAPI *decode1)(u8 *data, const char *pass, PCRYPTO_INFO *ci); +extern void(MDSXDLLAPI *decryptMdxData)(Decoder *ctx, u8 *buffer, u32 length, u64 blockSize, u64 blockIndex); +extern int(MDSXDLLAPI *Gf128Tab64Init)(uint8_t *a, GfCtx *ctx); +extern AES_RETURN(MDSXDLLAPI *aes_encrypt_key)(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1]); +extern AES_RETURN(MDSXDLLAPI *aes_decrypt_key)(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1]); + +extern void mdsx_close(void); +extern int mdsx_init(void); +#endif + + +// utils.c +inline static u64 getU64(const void *mem) +{ + const u8 *mem8 = (const u8 *)mem; + return ((u64)mem8[0] | ((u64)mem8[1] << 8) | ((u64)mem8[2] << 16) | ((u64)mem8[3] << 24) | ((u64)mem8[4] << 32) | ((u64)mem8[5] << 40) | ((u64)mem8[6] << 48) | ((u64)mem8[7] << 56)); +} + +inline static u32 getU32(const void *mem) +{ + const u8 *mem8 = (const u8 *)mem; + return ((u32)mem8[0] | ((u32)mem8[1] << 8) | ((u32)mem8[2] << 16) | ((u32)mem8[3] << 24)); +} + +inline static u16 getU16(const void *mem) +{ + const u8 *mem8 = (const u8 *)mem; + return ((u16)mem8[0] | ((u16)mem8[1] << 8)); +} + +inline static u8 getU8(const void *mem) +{ + const u8 *mem8 = (const u8 *)mem; + return (u8)mem8[0]; +} + +inline static void setU32(void *mem, u32 val) +{ + u8 *mem8 = (u8 *)mem; + mem8[0] = val & 0xff; + mem8[1] = (val >> 8) & 0xff; + mem8[2] = (val >> 16) & 0xff; + mem8[3] = (val >> 24) & 0xff; +} + +u32 freadU32(FILE *f); +u64 freadU64(FILE *f); +void printHex(void *data, int num); + +#endif diff --git a/src/utils/mdsx_dll.c b/src/utils/mdsx_dll.c new file mode 100644 index 00000000000..87beff441ca --- /dev/null +++ b/src/utils/mdsx_dll.c @@ -0,0 +1,90 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of a generic PostScript printer and a + * generic PCL 5e printer. + * + * Authors: David Hrdlička, + * Cacodemon345 + * + * Copyright 2019 David Hrdlička. + * Copyright 2024 Cacodemon345. + */ +#include +#include +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/timer.h> +#include <86box/device.h> +#include <86box/lpt.h> +#include <86box/pit.h> +#include <86box/path.h> +#include <86box/plat.h> +#include <86box/plat_dynld.h> +#include <86box/ui.h> +#include <86box/prt_devs.h> +#include "cpu.h" +#include "defines.h" +#include "mds.h" + +#ifdef _WIN32 +# define PATH_MDSX_DLL "mdsx.dll" +#elif defined __APPLE__ +# define PATH_MDSX_DLL "mdsx.dylib" +#else +# define PATH_MDSX_DLL "mdsx.so" +#endif + +void(MDSXDLLAPI *DecryptBlock)(u8 *buf, TC_LARGEST_COMPILER_UINT len, u32 secSz, u64 secN, u8 flags, PCRYPTO_INFO cryptoInfo); +int(MDSXDLLAPI *decode1)(u8 *data, const char *pass, PCRYPTO_INFO *ci); +void(MDSXDLLAPI *decryptMdxData)(Decoder *ctx, u8 *buffer, u32 length, u64 blockSize, u64 blockIndex); +int(MDSXDLLAPI *Gf128Tab64Init)(uint8_t *a, GfCtx *ctx); +AES_RETURN(MDSXDLLAPI *aes_encrypt_key)(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1]); +AES_RETURN(MDSXDLLAPI *aes_decrypt_key)(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1]); + +static dllimp_t mdsx_imports[] = { + // clang-format off + { "DecryptBlock", &DecryptBlock }, + { "decode1", &decode1 }, + { "decryptMdxData", &decryptMdxData }, + { "Gf128Tab64Init", &Gf128Tab64Init }, + { "aes_encrypt_key", &aes_encrypt_key }, + { "aes_decrypt_key", &aes_decrypt_key }, + { NULL, NULL } + // clang-format on +}; + +static void *mdsx_handle = NULL; + +void +mdsx_close(void) +{ + if (mdsx_handle != NULL) { + dynld_close(mdsx_handle); + mdsx_handle = NULL; + } +} + +int +mdsx_init(void) +{ + /* Try loading the DLL. */ + mdsx_handle = dynld_module(PATH_MDSX_DLL, mdsx_imports); + + if (mdsx_handle == NULL) { + warning("Unable to load %s\n", PATH_MDSX_DLL); + return 0; + } + + return 1; +} diff --git a/src/utils/random.c b/src/utils/random.c index 6ed6c1d0c4f..5658bc3fbb5 100644 --- a/src/utils/random.c +++ b/src/utils/random.c @@ -51,16 +51,10 @@ rdtsc(void) #if defined(__x86_64__) unsigned int hi; unsigned int lo; -# ifdef _MSC_VER - __asm { - rdtsc - mov hi, edx ; EDX:EAX is already standard return!! - mov lo, eax - } -# else + __asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi)); -# endif + return ((unsigned long long) lo) | (((unsigned long long) hi) << 32); #else return time(NULL); diff --git a/src/video/ramdac/vid_ramdac_bt48x.c b/src/video/ramdac/vid_ramdac_bt48x.c index 2133e02a03c..52e5a7bd2d8 100644 --- a/src/video/ramdac/vid_ramdac_bt48x.c +++ b/src/video/ramdac/vid_ramdac_bt48x.c @@ -377,7 +377,9 @@ bt48x_recalctimings(void *priv, svga_t *svga) if (svga->bpp >= 15) svga->true_color_bypass = !!(ramdac->cmd_r1 & 0x10); +#if 0 pclog("CR0=%02x, CR1=%02x, CR2=%02x.\n", ramdac->cmd_r0, ramdac->cmd_r1, ramdac->cmd_r2); +#endif } void diff --git a/src/video/vid_ati28800.c b/src/video/vid_ati28800.c index 2fe46bea311..6a6b0723d9f 100644 --- a/src/video/vid_ati28800.c +++ b/src/video/vid_ati28800.c @@ -574,16 +574,16 @@ ati28800k_init(const device_t *info) default: case 0: rom_init(&ati28800->bios_rom, BIOS_ATIKOR_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - loadfont(FONT_ATIKOR_PATH, 6); + video_load_font(FONT_ATIKOR_PATH, FONT_FORMAT_KSC6501, LOAD_FONT_NO_OFFSET); break; case 1: rom_init_interleaved(&ati28800->bios_rom, BIOS_ATIKOR_4620P_PATH_L, BIOS_ATIKOR_4620P_PATH_H, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - loadfont(FONT_ATIKOR_4620P_PATH, 6); + video_load_font(FONT_ATIKOR_4620P_PATH, FONT_FORMAT_KSC6501, LOAD_FONT_NO_OFFSET); break; case 2: rom_init(&ati28800->bios_rom, BIOS_ATIKOR_6033P_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - loadfont(FONT_ATIKOR_6033P_PATH, 6); + video_load_font(FONT_ATIKOR_6033P_PATH, FONT_FORMAT_KSC6501,LOAD_FONT_NO_OFFSET); break; } @@ -838,7 +838,7 @@ const device_t ati28800k_device = { }; const device_t ati28800k_spc4620p_device = { - .name = "ATI Korean VGA On-Board SPC-4620P", + .name = "ATI Korean VGA On-Board (Samsung SPC-4620P)", .internal_name = "ati28800k_spc4620p", .flags = DEVICE_ISA, .local = 1, @@ -852,7 +852,7 @@ const device_t ati28800k_spc4620p_device = { }; const device_t ati28800k_spc6033p_device = { - .name = "ATI Korean VGA On-Board SPC-6033P", + .name = "ATI Korean VGA On-Board (Samsung SPC-6033P)", .internal_name = "ati28800k_spc6033p", .flags = DEVICE_ISA, .local = 2, diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index 9aa8b687db8..ceaf4224b84 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -79,7 +79,8 @@ enum { MACH64_GX = 0, MACH64_CT, MACH64_VT, - MACH64_VT2 + MACH64_VT2, + MACH64_VT3 }; typedef struct mach64_t { @@ -138,6 +139,8 @@ typedef struct mach64_t { uint32_t cur_horz_vert_posn; uint32_t cur_offset; + uint32_t gp_io; + uint32_t dac_cntl; uint32_t dp_bkgd_clr; @@ -145,6 +148,7 @@ typedef struct mach64_t { uint32_t dp_mix; uint32_t dp_pix_width; uint32_t dp_src; + uint32_t dp_set_gui_engine; uint32_t dst_bres_lnth; uint32_t dst_bres_dec; @@ -177,6 +181,8 @@ typedef struct mach64_t { uint32_t scratch_reg0; uint32_t scratch_reg1; + uint32_t scratch_reg2; + uint32_t scratch_reg3; uint32_t src_cntl; uint32_t src_off_pitch; @@ -229,6 +235,7 @@ typedef struct mach64_t { int pattern[8][8]; uint8_t pattern_clr4x2[2][4]; uint8_t pattern_clr8x1[8]; + uint8_t pattern_clr8x8[8][8]; int sc_left; int sc_right; int sc_top; @@ -254,10 +261,22 @@ typedef struct mach64_t { int poly_draw; } accel; +#ifdef DMA_BM + struct { + ATOMIC_INT state; + + ATOMIC_UINT frame_buf_offset, system_buf_addr, command, status; + + ATOMIC_BOOL system_triggered; + + mutex_t *lock; + } dma; +#endif + fifo_entry_t fifo[FIFO_SIZE]; - atomic_int fifo_read_idx; - atomic_int fifo_write_idx; - atomic_int blitter_busy; + ATOMIC_INT fifo_read_idx; + ATOMIC_INT fifo_write_idx; + ATOMIC_INT blitter_busy; thread_t *fifo_thread; event_t *wake_fifo_thread; @@ -299,6 +318,15 @@ typedef struct mach64_t { uint32_t buf_offset[2]; uint32_t buf_pitch[2]; + uint32_t scaler_buf_offset[2]; + uint32_t scaler_buf_pitch; + uint32_t overlay_exclusive_horz, overlay_exclusive_vert; + + uint32_t vga_dsp_config; + uint32_t vga_dsp_on_off; + uint32_t dsp_config; + uint32_t dsp_on_off; + int overlay_v_acc; uint32_t overlay_uv_addr; @@ -307,6 +335,7 @@ typedef struct mach64_t { uint8_t thread_run; void *i2c; + void *i2c_tv; void *ddc; } mach64_t; @@ -348,7 +377,10 @@ enum { SRC_PATT_EN = 1, SRC_PATT_ROT_EN = 2, SRC_LINEAR_EN = 4, - SRC_BYTE_ALIGN = 8 + SRC_BYTE_ALIGN = 8, + SRC_8x8x8_BRUSH = 32, + + SRC_8x8x8_BRUSH_LOADED = 1 << 12 }; enum { @@ -415,6 +447,8 @@ mach64_log(const char *fmt, ...) # define mach64_log(fmt, ...) #endif +static mach64_t *reset_state[2] = { NULL, NULL }; + void mach64_out(uint16_t addr, uint8_t val, void *priv) { @@ -529,6 +563,7 @@ mach64_recalctimings(svga_t *svga) const mach64_t *mach64 = (mach64_t *) svga->priv; if (((mach64->crtc_gen_cntl >> 24) & 3) == 3) { + svga->char_width = 8; svga->vtotal = (mach64->crtc_v_total_disp & 2047) + 1; svga->dispend = ((mach64->crtc_v_total_disp >> 16) & 2047) + 1; svga->htotal = (mach64->crtc_h_total_disp & 255) + 1; @@ -559,34 +594,40 @@ mach64_recalctimings(svga_t *svga) if (mach64->type != MACH64_GX) svga->render = svga_render_4bpp_highres; svga->hdisp <<= 3; + svga->bpp = 4; break; case BPP_8: if (mach64->type != MACH64_GX) svga->render = svga_render_8bpp_clone_highres; svga->hdisp <<= 3; svga->rowoffset >>= 1; + svga->bpp = 8; break; case BPP_15: if (mach64->type != MACH64_GX) svga->render = svga_render_15bpp_highres; svga->hdisp <<= 3; + svga->bpp = 15; break; case BPP_16: if (mach64->type != MACH64_GX) svga->render = svga_render_16bpp_highres; svga->hdisp <<= 3; + svga->bpp = 16; break; case BPP_24: if (mach64->type != MACH64_GX) svga->render = svga_render_24bpp_highres; svga->hdisp <<= 3; svga->rowoffset = (svga->rowoffset * 3) / 2; + svga->bpp = 24; break; case BPP_32: if (mach64->type != MACH64_GX) svga->render = svga_render_32bpp_highres; svga->hdisp <<= 3; svga->rowoffset <<= 1; + svga->bpp = 32; break; default: @@ -597,6 +638,7 @@ mach64_recalctimings(svga_t *svga) } else { svga->vram_display_mask = (mach64->regs[0x36] & 0x01) ? mach64->vram_mask : 0x3ffff; svga->lut_map = 0; + svga->bpp = 8; } } @@ -737,6 +779,154 @@ mach64_wait_fifo_idle(mach64_t *mach64) break; \ } + +static void +mach64_accel_write_fifo_l(mach64_t *mach64, uint32_t addr, uint32_t val); + +static void +mach64_recalc_dp_set_engine(mach64_t *mach64) +{ + static const unsigned int pitches[16] = + { + [0] = 320, // fallback + [1] = 320, + [2] = 352, + [3] = 384, + [4] = 640, + [5] = 800, + [6] = 896, + [7] = 512, + [8] = 1024, + [9] = 1152, + [10] = 1280, + [11] = 400, + [12] = 832, + [13] = 1600, + [14] = 448, + [15] = 2048 + }; + + mach64->dst_y_x = 0; + mach64->dst_height_width = 0; + mach64->src_y_x = 0; + mach64->sc_top_bottom = 0x3FFF0000; + mach64->sc_left_right = 0x1FFF0000; + mach64->write_mask = ~0u; + mach64->clr_cmp_clr = 0; + mach64->src_y_x_start = 0; + mach64->src_cntl &= ~((3 << 13) | (1 << 5) | (1 << 12)); + mach64->dst_cntl &= ~(7 << 13); + mach64->dp_pix_width &= (1 << 13); + + mach64->dp_pix_width = (mach64->dp_pix_width & ~7) | ((mach64->dp_set_gui_engine >> 3) & 7); + mach64->dp_pix_width = (mach64->dp_pix_width & ~(0xf << 8)) | ((mach64->dp_set_gui_engine & (1 << 6)) ? ((mach64->dp_pix_width & 7) << 8) : 0); + + mach64->dst_off_pitch = (262144 * ((mach64->dp_set_gui_engine >> 7) & 3)) & ((1 << 20) - 1); + mach64->dst_off_pitch |= (((pitches[(mach64->dp_set_gui_engine >> 10) & 0xF]) * ((mach64->dp_set_gui_engine & (1 << 14)) ? 2 : 1)) / 8) << 22; + + mach64->src_off_pitch = 0; + if (mach64->dp_set_gui_engine & (1 << 15)) + mach64->src_off_pitch = mach64->dst_off_pitch; + + switch ((mach64->dp_set_gui_engine >> 16) & 3) + { + case 0: + mach64->src_height1_width1 = mach64->src_height2_width2 = (0x00080008); + break; + case 1: + mach64->src_height1_width1 = mach64->src_height2_width2 = (0x00200001); + break; + case 2: + mach64->src_height1_width1 = mach64->src_height2_width2 = (0x00180008); + break; + } + + switch ((mach64->dp_set_gui_engine >> 20) & 0xf) + { + case 0: + { + pclog("unknown drawing combo2\n"); + break; + } + case 1: + mach64->dp_mix = 0x070003; + mach64->dp_src = 0x0000100; + mach64->gui_traj_cntl = 0x23; + break; + case 2: + mach64->dp_src = 0x200; + mach64->dp_mix = 0x70007; + mach64->gui_traj_cntl = 0x3; + break; + case 3: + mach64->dp_src = 0x20100; + mach64->dp_mix = 0x70007; + mach64->gui_traj_cntl = 0x3; + break; + case 4: + mach64->dp_src = 0x100; + mach64->dp_mix = 0x70007; + mach64->gui_traj_cntl = 0x3; + break; + case 5: + mach64->dp_src = 0x10100; + mach64->dp_mix = 0x70007; + mach64->gui_traj_cntl = 0x01000003; + break; + case 6: + mach64->dp_src = 0x100; + mach64->dp_mix = 0x70007; + mach64->gui_traj_cntl = 0x3; + break; + case 7: + mach64->dp_src = 0x300; + mach64->dp_mix = 0x70007; + mach64->gui_traj_cntl = 0x30003; + break; + case 8: + mach64->dp_src = 0x300; + mach64->dp_mix = 0x70007; + mach64->gui_traj_cntl = 0; + break; + case 9: + mach64->dp_src = 0x300; + mach64->dp_mix = 0x70007; + mach64->gui_traj_cntl = 1; + break; + case 10: + mach64->dp_src = 0x300; + mach64->dp_mix = 0x70007; + mach64->gui_traj_cntl = 2; + break; + case 11: + mach64->dp_src = 0x300; + mach64->dp_mix = 0x70007; + mach64->gui_traj_cntl = 3; + break; + case 12: + mach64->dp_src = 0x20100; + mach64->dp_mix = 0x70003; + mach64->gui_traj_cntl = 0x1004001B; + break; + case 13: + mach64->dp_src = 0x20100; + mach64->dp_mix = 0x70003; + mach64->gui_traj_cntl = 0x0004001B; + break; + case 14: + { + pclog("unknown drawing combo\n"); + break; + } + case 15: + mach64->dp_src = 0x300; + mach64->dp_mix = 0x70007; + mach64->gui_traj_cntl = 0x0004001B; + break; + } + mach64_accel_write_fifo_l(mach64, 0x330, mach64->gui_traj_cntl); +} + static void mach64_accel_write_fifo(mach64_t *mach64, uint32_t addr, uint8_t val) { @@ -763,6 +953,12 @@ mach64_accel_write_fifo(mach64_t *mach64, uint32_t addr, uint8_t val) case 0x10f: WRITE8(addr, mach64->dst_y_x, val); break; + case 0x2e8: + case 0x2e9: + case 0x2ea: + case 0x2eb: + WRITE8(addr ^ 2, mach64->dst_y_x, val); + break; case 0x110: case 0x111: WRITE8(addr + 2, mach64->dst_height_width, val); @@ -779,6 +975,7 @@ mach64_accel_write_fifo(mach64_t *mach64, uint32_t addr, uint8_t val) fallthrough; case 0x113: if (((addr & 0x3ff) == 0x11b || (addr & 0x3ff) == 0x11f || (addr & 0x3ff) == 0x113) && !(val & 0x80)) { +start_blit_op: mach64_start_fill(mach64); mach64_log("%i %i %i %i %i %08x\n", (mach64->dst_height_width & 0x7ff), (mach64->dst_height_width & 0x7ff0000), ((mach64->dp_src & 7) != SRC_HOST), (((mach64->dp_src >> 8) & 7) != SRC_HOST), @@ -788,6 +985,16 @@ mach64_accel_write_fifo(mach64_t *mach64, uint32_t addr, uint8_t val) } break; + case 0x2ec: + case 0x2ed: + case 0x2ee: + case 0x2ef: + WRITE8(addr ^ 2, mach64->dst_height_width, val); + if ((addr & 0x3ff) == 0x2ef) { + goto start_blit_op; + } + break; + case 0x120: case 0x121: case 0x122: @@ -894,6 +1101,12 @@ mach64_accel_write_fifo(mach64_t *mach64, uint32_t addr, uint8_t val) case 0x1b6: case 0x1b7: WRITE8(addr, mach64->src_cntl, val); +#ifdef DMA_BM + if (mach64->src_cntl & (1 << 9)) + pclog("Bus master enabled\n"); + else + pclog("Bus master disabled\n"); +#endif break; case 0x200: @@ -1063,6 +1276,13 @@ mach64_accel_write_fifo(mach64_t *mach64, uint32_t addr, uint8_t val) case 0x2db: WRITE8(addr, mach64->dp_src, val); break; + case 0x2fc: + case 0x2fd: + case 0x2fe: + case 0x2ff: + WRITE8(addr, mach64->dp_set_gui_engine, val); + mach64_recalc_dp_set_engine(mach64); + break; case 0x300: case 0x301: @@ -1148,6 +1368,16 @@ mach64_accel_write_fifo_w(mach64_t *mach64, uint32_t addr, uint16_t val) mach64_blit(val, 16, mach64); break; + case 0x2fc: + mach64->dp_set_gui_engine |= (mach64->dp_set_gui_engine & 0xffff0000) | val; + mach64_recalc_dp_set_engine(mach64); + break; + + case 0x2fe: + mach64->dp_set_gui_engine |= (mach64->dp_set_gui_engine & 0xffff) | (val << 16); + mach64_recalc_dp_set_engine(mach64); + break; + case 0x32c: mach64->context_load_cntl = (mach64->context_load_cntl & 0xffff0000) | val; break; @@ -1196,6 +1426,11 @@ mach64_accel_write_fifo_l(mach64_t *mach64, uint32_t addr, uint32_t val) mach64_blit(((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24), 32, mach64); break; + case 0x2fc: + mach64->dp_set_gui_engine = val; + mach64_recalc_dp_set_engine(mach64); + break; + default: mach64_accel_write_fifo_w(mach64, addr, val); mach64_accel_write_fifo_w(mach64, addr + 2, val >> 16); @@ -1203,6 +1438,18 @@ mach64_accel_write_fifo_l(mach64_t *mach64, uint32_t addr, uint32_t val) } } +#ifdef DMA_BM +static void +run_dma(mach64_t *mach64) +{ + int words_transferred = 0; + + thread_wait_mutex(mach64->dma.lock); + thread_release_mutex(mach64->dma.lock); + +} +#endif + static void fifo_thread(void *param) { @@ -1243,6 +1490,9 @@ fifo_thread(void *param) end_time = plat_timer_read(); mach64->blitter_time += end_time - start_time; } +#ifdef DMA_BM + run_dma(mach64); +#endif mach64->blitter_busy = 0; } } @@ -1433,6 +1683,13 @@ mach64_start_fill(mach64_t *mach64) mach64->accel.pattern_clr8x1[7] = ((mach64->pat_reg1 >> 24) & 0xff); } + if ((mach64->src_cntl & SRC_8x8x8_BRUSH) && !(mach64->src_cntl & SRC_8x8x8_BRUSH_LOADED)) + { + for (int y = 0; y < 8; y++) + for (int x = 0; x < 8; x++) + mach64->accel.pattern_clr8x8[y][x] = mach64->svga.vram[(mach64->accel.src_offset & ~7) + (y * 8) + x]; + } + mach64->accel.sc_left = mach64->sc_left_right & 0x1fff; mach64->accel.sc_right = (mach64->sc_left_right >> 16) & 0x1fff; mach64->accel.sc_top = mach64->sc_top_bottom & 0x7fff; @@ -1450,7 +1707,6 @@ mach64_start_fill(mach64_t *mach64) mach64->accel.poly_draw = 0; mach64->accel.busy = 1; - mach64_log("mach64_start_fill : dst %i, %i src %i, %i size %i, %i src pitch %i offset %X dst pitch %i offset %X scissor %i %i %i %i src_fg %i mix %02X %02X\n", mach64->accel.dst_x_start, mach64->accel.dst_y_start, mach64->accel.src_x_start, mach64->accel.src_y_start, mach64->accel.dst_width, mach64->accel.dst_height, mach64->accel.src_pitch, mach64->accel.src_offset, mach64->accel.dst_pitch, mach64->accel.dst_offset, mach64->accel.sc_left, mach64->accel.sc_right, mach64->accel.sc_top, mach64->accel.sc_bottom, mach64->accel.source_fg, mach64->accel.mix_fg, mach64->accel.mix_bg); mach64->accel.op = OP_RECT; } @@ -1513,7 +1769,6 @@ mach64_start_line(mach64_t *mach64) } } } - mach64->accel.sc_left = mach64->sc_left_right & 0x1fff; mach64->accel.sc_right = (mach64->sc_left_right >> 16) & 0x1fff; mach64->accel.sc_top = mach64->sc_top_bottom & 0x7fff; @@ -1726,7 +1981,10 @@ mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) src_dat = host_dat; break; case SRC_BLITSRC: - READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, src_dat, mach64->accel.src_size); + if (mach64->accel.src_size == 0 && mach64->type == MACH64_VT3 && (mach64->src_cntl & SRC_8x8x8_BRUSH)) + src_dat = mach64->accel.pattern_clr8x8[dst_y & 7][dst_x & 7]; + else + READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, src_dat, mach64->accel.src_size); break; case SRC_FG: if (mach64->dst_cntl & DST_24_ROT_EN) { @@ -1911,6 +2169,14 @@ mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) uint32_t dest_dat; uint32_t host_dat = 0; int mix = 0; + int draw_pixel = !(mach64->dst_cntl & DST_POLYGON_EN); + + if (mach64->dst_cntl & DST_POLYGON_EN) { + if (mach64->dst_cntl & DST_Y_MAJOR) + draw_pixel = 1; + else if (mach64->accel.err >= 0) + draw_pixel = 1; + } if (mach64->accel.source_host) { host_dat = cpu_dat; @@ -1957,13 +2223,16 @@ mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) break; } - if ((mach64->accel.dst_x >= mach64->accel.sc_left) && (mach64->accel.dst_x <= mach64->accel.sc_right) && (mach64->accel.dst_y >= mach64->accel.sc_top) && (mach64->accel.dst_y <= mach64->accel.sc_bottom)) { + if ((mach64->accel.dst_x >= mach64->accel.sc_left) && (mach64->accel.dst_x <= mach64->accel.sc_right) && (mach64->accel.dst_y >= mach64->accel.sc_top) && (mach64->accel.dst_y <= mach64->accel.sc_bottom) && draw_pixel) { switch (mix ? mach64->accel.source_fg : mach64->accel.source_bg) { case SRC_HOST: src_dat = host_dat; break; case SRC_BLITSRC: - READ(mach64->accel.src_offset + (mach64->accel.src_y * mach64->accel.src_pitch) + mach64->accel.src_x, src_dat, mach64->accel.src_size); + if (mach64->accel.src_size == 0 && mach64->type == MACH64_VT3 && (mach64->src_cntl & SRC_8x8x8_BRUSH)) + src_dat = mach64->accel.pattern_clr8x8[mach64->accel.dst_y & 7][mach64->accel.dst_x & 7]; + else + READ(mach64->accel.src_offset + (mach64->accel.src_y * mach64->accel.src_pitch) + mach64->accel.src_x, src_dat, mach64->accel.src_size); break; case SRC_FG: src_dat = mach64->accel.dp_frgd_clr; @@ -2024,17 +2293,21 @@ mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) if (mach64->dst_cntl & DST_Y_MAJOR) { mach64->accel.dst_y += mach64->accel.yinc; + mach64->accel.src_y += mach64->accel.yinc; if (mach64->accel.err >= 0) { mach64->accel.err += mach64->dst_bres_dec; mach64->accel.dst_x += mach64->accel.xinc; + mach64->accel.src_x += mach64->accel.xinc; } else { mach64->accel.err += mach64->dst_bres_inc; } } else { mach64->accel.dst_x += mach64->accel.xinc; + mach64->accel.src_x += mach64->accel.xinc; if (mach64->accel.err >= 0) { mach64->accel.err += mach64->dst_bres_dec; mach64->accel.dst_y += mach64->accel.yinc; + mach64->accel.src_y += mach64->accel.yinc; } else { mach64->accel.err += mach64->dst_bres_inc; } @@ -2086,9 +2359,7 @@ mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) if (mach64->dst_cntl & DST_POLYGON_EN) { if (mach64->dst_cntl & DST_Y_MAJOR) draw_pixel = 1; - else if ((mach64->dst_cntl & DST_X_DIR) && mach64->accel.err < (mach64->dst_bres_dec + mach64->dst_bres_inc)) /*X+*/ - draw_pixel = 1; - else if (!(mach64->dst_cntl & DST_X_DIR) && mach64->accel.err >= 0) /*X-*/ + else if (mach64->accel.err >= 0) draw_pixel = 1; } @@ -2145,62 +2416,27 @@ mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) return; } - switch (mach64->dst_cntl & 7) { - case 0: - case 2: - mach64->accel.src_x--; - mach64->accel.dst_x--; - break; - case 1: - case 3: - mach64->accel.src_x++; - mach64->accel.dst_x++; - break; - case 4: - case 5: - mach64->accel.src_y--; - mach64->accel.dst_y--; - break; - case 6: - case 7: - mach64->accel.src_y++; - mach64->accel.dst_y++; - break; - - default: - break; - } - mach64_log("x %i y %i err %i inc %i dec %i\n", mach64->accel.dst_x, mach64->accel.dst_y, mach64->accel.err, mach64->dst_bres_inc, mach64->dst_bres_dec); - if (mach64->accel.err >= 0) { - mach64->accel.err += mach64->dst_bres_dec; - - switch (mach64->dst_cntl & 7) { - case 0: - case 1: - mach64->accel.src_y--; - mach64->accel.dst_y--; - break; - case 2: - case 3: - mach64->accel.src_y++; - mach64->accel.dst_y++; - break; - case 4: - case 6: - mach64->accel.src_x--; - mach64->accel.dst_x--; - break; - case 5: - case 7: - mach64->accel.src_x++; - mach64->accel.dst_x++; - break; - - default: - break; + if (mach64->dst_cntl & DST_Y_MAJOR) { + mach64->accel.dst_y += mach64->accel.yinc; + mach64->accel.src_y += mach64->accel.yinc; + if (mach64->accel.err >= 0) { + mach64->accel.err += mach64->dst_bres_dec; + mach64->accel.dst_x += mach64->accel.xinc; + mach64->accel.src_x += mach64->accel.xinc; + } else { + mach64->accel.err += mach64->dst_bres_inc; } - } else - mach64->accel.err += mach64->dst_bres_inc; + } else { + mach64->accel.dst_x += mach64->accel.xinc; + mach64->accel.src_x += mach64->accel.xinc; + if (mach64->accel.err >= 0) { + mach64->accel.err += mach64->dst_bres_dec; + mach64->accel.dst_y += mach64->accel.yinc; + mach64->accel.src_y += mach64->accel.yinc; + } else { + mach64->accel.err += mach64->dst_bres_inc; + } + } } } break; @@ -2328,8 +2564,13 @@ mach64_vblank_start(svga_t *svga) svga->overlay.cur_xsize = ((mach64->overlay_y_x_end >> 16) & 0x7ff) - svga->overlay.x; svga->overlay.cur_ysize = (mach64->overlay_y_x_end & 0x7ff) - svga->overlay.y; - svga->overlay.addr = mach64->buf_offset[0] & 0x3ffff8; - svga->overlay.pitch = mach64->buf_pitch[0] & 0xfff; + if (mach64->type >= MACH64_VT3) { + svga->overlay.addr = mach64->scaler_buf_offset[0] & 0x3fffff; + svga->overlay.pitch = mach64->scaler_buf_pitch & 0xfff; + } else { + svga->overlay.addr = mach64->buf_offset[0] & 0x3ffff8; + svga->overlay.pitch = mach64->buf_pitch[0] & 0xfff; + } svga->overlay.ena = (mach64->overlay_scale_cntl & OVERLAY_EN) && (overlay_cmp_mix != 1); @@ -2412,6 +2653,41 @@ mach64_ext_readb(uint32_t addr, void *priv) READ8(addr, mach64->scaler_height_width); break; + case 0x34: + case 0x35: + case 0x36: + case 0x37: + READ8(addr, mach64->scaler_buf_offset[0]); + break; + + case 0x38: + case 0x39: + case 0x3a: + case 0x3b: + READ8(addr, mach64->scaler_buf_offset[1]); + break; + + case 0x3c: + case 0x3d: + case 0x3e: + case 0x3f: + READ8(addr, mach64->scaler_buf_pitch); + break; + + case 0x58: + case 0x59: + case 0x5a: + case 0x5b: + READ8(addr, mach64->overlay_exclusive_horz); + break; + + case 0x5c: + case 0x5d: + case 0x5e: + case 0x5f: + READ8(addr, mach64->overlay_exclusive_vert); + break; + case 0x4a: ret = mach64->scaler_format; break; @@ -2476,6 +2752,20 @@ mach64_ext_readb(uint32_t addr, void *priv) READ8(addr, mach64->crtc_gen_cntl); break; + case 0x20: + case 0x21: + case 0x22: + case 0x23: + READ8(addr, mach64->dsp_config); + break; + + case 0x24: + case 0x25: + case 0x26: + case 0x27: + READ8(addr, mach64->dsp_on_off); + break; + case 0x40: case 0x41: case 0x42: @@ -2494,6 +2784,18 @@ mach64_ext_readb(uint32_t addr, void *priv) case 0x4b: READ8(addr, mach64->ovr_wid_top_bottom); break; + case 0x4c: + case 0x4d: + case 0x4e: + case 0x4f: + READ8(addr, mach64->vga_dsp_config); + break; + case 0x50: + case 0x51: + case 0x52: + case 0x53: + READ8(addr, mach64->vga_dsp_on_off); + break; case 0x60: case 0x61: @@ -2528,8 +2830,29 @@ mach64_ext_readb(uint32_t addr, void *priv) case 0x79: ret = 0x30; + if (mach64->type == MACH64_VT3) + { + ret = (((i2c_gpio_get_scl(mach64->i2c_tv) << 3)) & (~(mach64->gp_io >> 24) & 0xFF)) | ((mach64->gp_io >> 8) & (mach64->gp_io >> 24) & 0xFF); + ret &= ~((1 << 4) | (1 << 5)); + ret |= (i2c_gpio_get_scl(mach64->i2c) << 5) | (i2c_gpio_get_sda(mach64->i2c) << 4); + break; + } break; + case 0x78: + if (mach64->type == MACH64_VT3) + { + ret = ((i2c_gpio_get_sda(mach64->i2c_tv) << 4) & (~(mach64->gp_io >> 16) & 0xFF)) | ((mach64->gp_io & 0xFF) & ((mach64->gp_io >> 16) & 0xFF)); + break; + } + case 0x7A: + case 0x7B: + if (mach64->type == MACH64_VT3) + { + READ8(addr, mach64->gp_io); + } +// pclog("GPIO READ 0x%X, 0x00\n", addr & 0x3ff); + break; case 0x80: case 0x81: case 0x82: @@ -2588,7 +2911,7 @@ mach64_ext_readb(uint32_t addr, void *priv) case 0xc7: READ8(addr, mach64->dac_cntl); - if (mach64->type >= MACH64_CT) { + if (mach64->type >= MACH64_CT && mach64->type != MACH64_VT3) { ret &= 0xf9; if (i2c_gpio_get_scl(mach64->i2c)) ret |= 0x04; @@ -2654,6 +2977,21 @@ mach64_ext_readb(uint32_t addr, void *priv) mach64_wait_fifo_idle(mach64); READ8(addr, mach64->dst_y_x); break; + case 0x2e8: + case 0x2e9: + case 0x2ea: + case 0x2eb: + mach64_wait_fifo_idle(mach64); + READ8(addr ^ 2, mach64->dst_y_x); + break; + case 0x2ec: + case 0x2ed: + case 0x2ee: + case 0x2ef: + mach64_wait_fifo_idle(mach64); + READ8(addr ^ 2, mach64->dst_height_width); + break; + case 0x110: case 0x111: addr += 2; @@ -2970,6 +3308,10 @@ mach64_ext_readb(uint32_t addr, void *priv) ret = FIFO_EMPTY ? 0 : 1; break; + case 0x33a: + ret = FIFO_EMPTY ? 32 : 31; + break; + default: ret = 0; break; @@ -3116,6 +3458,27 @@ mach64_ext_writeb(uint32_t addr, uint8_t val, void *priv) WRITE8(addr, mach64->scaler_height_width, val); break; + case 0x34: + case 0x35: + case 0x36: + case 0x37: + WRITE8(addr, mach64->scaler_buf_offset[0], val); + break; + + case 0x38: + case 0x39: + case 0x3a: + case 0x3b: + WRITE8(addr, mach64->scaler_buf_offset[1], val); + break; + + case 0x3c: + case 0x3d: + case 0x3e: + case 0x3f: + WRITE8(addr, mach64->scaler_buf_pitch, val); + break; + case 0x4a: mach64->scaler_format = val & 0xf; break; @@ -3124,6 +3487,20 @@ mach64_ext_writeb(uint32_t addr, uint8_t val, void *priv) mach64->scaler_yuv_aper = val; break; + case 0x58: + case 0x59: + case 0x5a: + case 0x5b: + WRITE8(addr, mach64->overlay_exclusive_horz, val); + break; + + case 0x5c: + case 0x5d: + case 0x5e: + case 0x5f: + WRITE8(addr, mach64->overlay_exclusive_vert, val); + break; + case 0x80: case 0x81: case 0x82: @@ -3225,6 +3602,34 @@ mach64_ext_writeb(uint32_t addr, uint8_t val, void *priv) svga->fullchange = svga->monitor->mon_changeframecount; break; + case 0x20: + case 0x21: + case 0x22: + case 0x23: + WRITE8(addr, mach64->dsp_config, val); + break; + + case 0x24: + case 0x25: + case 0x26: + case 0x27: + WRITE8(addr, mach64->dsp_on_off, val); + break; + + case 0x4c: + case 0x4d: + case 0x4e: + case 0x4f: + WRITE8(addr, mach64->vga_dsp_config, val); + break; + + case 0x50: + case 0x51: + case 0x52: + case 0x53: + WRITE8(addr, mach64->vga_dsp_on_off, val); + break; + case 0x40: case 0x41: case 0x42: @@ -3293,6 +3698,19 @@ mach64_ext_writeb(uint32_t addr, uint8_t val, void *priv) } break; + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + if (mach64->type == MACH64_VT3) { + WRITE8(addr, mach64->gp_io, val); + { + i2c_gpio_set(mach64->i2c_tv, !!(mach64->gp_io & (1 << 11)) || !(mach64->gp_io & (1 << (11 + 16))), !!(mach64->gp_io & (1 << 4)) || !(mach64->gp_io & (1 << (4 + 16)))); + i2c_gpio_set(mach64->i2c, !!(mach64->gp_io & (1 << 13)) || !(mach64->gp_io & (1 << (13 + 16))), !!(mach64->gp_io & (1 << 12)) || !(mach64->gp_io & (1 << (12 + 16)))); + } + } + break; + case 0x80: case 0x81: case 0x82: @@ -3380,7 +3798,8 @@ mach64_ext_writeb(uint32_t addr, uint8_t val, void *priv) if (mach64->type == MACH64_GX) ati68860_set_ramdac_type(svga->ramdac, !!(mach64->dac_cntl & 0x100)); } - i2c_gpio_set(mach64->i2c, !(mach64->dac_cntl & 0x20000000) || (mach64->dac_cntl & 0x04000000), !(mach64->dac_cntl & 0x10000000) || (mach64->dac_cntl & 0x02000000)); + if (mach64->type != MACH64_VT3) + i2c_gpio_set(mach64->i2c, !(mach64->dac_cntl & 0x20000000) || (mach64->dac_cntl & 0x04000000), !(mach64->dac_cntl & 0x10000000) || (mach64->dac_cntl & 0x02000000)); break; case 0xd0: @@ -4293,6 +4712,9 @@ mach64_overlay_draw(svga_t *svga, int displine) int video_key_fn = mach64->overlay_key_cntl & 5; int graphics_key_fn = (mach64->overlay_key_cntl >> 4) & 5; int overlay_cmp_mix = (mach64->overlay_key_cntl >> 8) & 0xf; + int gfx_src = 0; + int desktop_x = mach64->svga.overlay_latch.x; + int desktop_y = displine - svga->y_add; p = &buffer32->line[displine][svga->x_add + mach64->svga.overlay_latch.x]; @@ -4365,6 +4787,23 @@ mach64_overlay_draw(svga_t *svga, int displine) default: break; } + switch (svga->bpp) { + case 8: + gfx_src = svga->vram[desktop_y * (svga->rowoffset * 8) + (desktop_x + x) * 1 + svga->memaddr_latch * 4]; + break; + case 15: + case 16: + gfx_src = *(uint16_t*)&svga->vram[desktop_y * (svga->rowoffset * 8) + (desktop_x + x) * 2 + svga->memaddr_latch * 4]; + break; + case 24: + gfx_src = svga->vram[desktop_y * (svga->rowoffset * 8) + (desktop_x + x) * 3 + svga->memaddr_latch * 4] + | (svga->vram[desktop_y * (svga->rowoffset * 8) + (desktop_x + x) * 3 + 1 + svga->memaddr_latch * 4] << 8) + | (svga->vram[desktop_y * (svga->rowoffset * 8) + (desktop_x + x) * 3 + 2 + svga->memaddr_latch * 4] << 16); + break; + case 32: + gfx_src = *(uint32_t*)&svga->vram[desktop_y * (svga->rowoffset * 8) + (desktop_x + x) * 4 + svga->memaddr_latch * 4]; + break; + } switch (graphics_key_fn) { case 0: gr_cmp = 0; @@ -4373,16 +4812,16 @@ mach64_overlay_draw(svga_t *svga, int displine) gr_cmp = 1; break; case 4: - gr_cmp = (((p[x]) ^ mach64->overlay_graphics_key_clr) & mach64->overlay_graphics_key_msk & 0xffffff); + gr_cmp = ((gfx_src ^ mach64->overlay_graphics_key_clr) & mach64->overlay_graphics_key_msk & 0xffffff); break; case 5: - gr_cmp = !(((p[x]) ^ mach64->overlay_graphics_key_clr) & mach64->overlay_graphics_key_msk & 0xffffff); + gr_cmp = !((gfx_src ^ mach64->overlay_graphics_key_clr) & mach64->overlay_graphics_key_msk & 0xffffff); break; default: break; } - vid_cmp = vid_cmp ? -1 : 0; + vid_cmp = vid_cmp ?-1 : 0; gr_cmp = gr_cmp ? -1 : 0; switch (overlay_cmp_mix) { @@ -4862,17 +5301,69 @@ mach64_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv) } } +static void +mach64_disable_handlers(mach64_t *dev) +{ + mach64_io_remove(dev); + + mem_mapping_disable(&dev->linear_mapping); + mem_mapping_disable(&dev->linear_mapping_big_endian); + mem_mapping_disable(&dev->mmio_mapping); + mem_mapping_disable(&dev->mmio_linear_mapping); + mem_mapping_disable(&dev->mmio_linear_mapping_2); + mem_mapping_disable(&dev->svga.mapping); + if (dev->pci && !dev->on_board) + mem_mapping_disable(&dev->bios_rom.mapping); + + /* Save all the mappings and the timers because they are part of linked lists. */ + reset_state[dev->svga.monitor_index]->linear_mapping = dev->linear_mapping; + reset_state[dev->svga.monitor_index]->linear_mapping_big_endian = dev->linear_mapping_big_endian; + reset_state[dev->svga.monitor_index]->mmio_mapping = dev->mmio_mapping; + reset_state[dev->svga.monitor_index]->mmio_linear_mapping = dev->mmio_linear_mapping; + reset_state[dev->svga.monitor_index]->mmio_linear_mapping_2 = dev->mmio_linear_mapping_2; + reset_state[dev->svga.monitor_index]->svga.mapping = dev->svga.mapping; + reset_state[dev->svga.monitor_index]->bios_rom.mapping = dev->bios_rom.mapping; + + reset_state[dev->svga.monitor_index]->svga.timer = dev->svga.timer; + reset_state[dev->svga.monitor_index]->svga.timer_8514 = dev->svga.timer_8514; + reset_state[dev->svga.monitor_index]->svga.timer_xga = dev->svga.timer_xga; +} + +static void +mach64_reset(void *priv) +{ + mach64_t *dev = (mach64_t *) priv; + + if (reset_state[dev->svga.monitor_index] != NULL) { + mach64_disable_handlers(dev); + dev->blitter_busy = 0; + dev->fifo_write_idx = 0; + dev->fifo_read_idx = 0; + reset_state[dev->svga.monitor_index]->eeprom = dev->eeprom; + reset_state[dev->svga.monitor_index]->pci_slot = dev->pci_slot; + + *dev = *reset_state[dev->svga.monitor_index]; + mach64_io_set(dev); + memset(dev->svga.vram, 0, dev->svga.vram_max); + memset(dev->svga.changedvram, 0, (dev->svga.vram_max >> 12) + 1); + dev->svga.dpms = 1; + svga_recalctimings(&dev->svga); + dev->svga.dpms = 0; + } +} + static void * mach64_common_init(const device_t *info) { svga_t *svga; mach64_t *mach64 = malloc(sizeof(mach64_t)); memset(mach64, 0, sizeof(mach64_t)); + reset_state[monitor_index_global] = calloc(1, sizeof(mach64_t)); svga = &mach64->svga; mach64->type = info->local & 0xff; - mach64->vram_size = (mach64->type == MACH64_CT || mach64->type == MACH64_VT) ? 2 : ((info->local & (1 << 20)) ? 4 : device_get_config_int("memory")); + mach64->vram_size = (mach64->type == MACH64_CT || mach64->type == MACH64_VT || mach64->type == MACH64_VT3) ? 2 : ((info->local & (1 << 20)) ? 4 : device_get_config_int("memory")); mach64->vram_mask = (mach64->vram_size << 20) - 1; if (mach64->type > MACH64_GX) @@ -4920,8 +5411,13 @@ mach64_common_init(const device_t *info) mach64->on_board = !!(info->local & (1 << 19)); mach64->i2c = i2c_gpio_init("ddc_ati_mach64"); + mach64->i2c_tv = i2c_gpio_init("tv_ati_mach64"); mach64->ddc = ddc_init(i2c_gpio_get_bus(mach64->i2c)); +#ifdef DMA_BM + mach64->dma.lock = thread_create_mutex(); +#endif + return mach64; } @@ -4965,6 +5461,7 @@ mach64gx_init(const device_t *info) rom_init(&mach64->bios_rom, BIOS_ISA_ROM_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); } + *reset_state[monitor_index_global] = *mach64; return mach64; } static void * @@ -4998,6 +5495,7 @@ mach64ct_init(const device_t *info) svga->vblank_start = mach64_vblank_start; svga->adv_flags |= FLAG_PANNING_ATI; + *reset_state[monitor_index_global] = *mach64; return mach64; } static void * @@ -5030,6 +5528,7 @@ mach64vt_init(const device_t *info) svga->vblank_start = mach64_vblank_start; svga->adv_flags |= FLAG_PANNING_ATI; + *reset_state[monitor_index_global] = *mach64; return mach64; } static void * @@ -5062,6 +5561,37 @@ mach64vt2_init(const device_t *info) svga->vblank_start = mach64_vblank_start; svga->adv_flags |= FLAG_PANNING_ATI; + *reset_state[monitor_index_global] = *mach64; + return mach64; +} + +static void * +mach64vt3_onboard_init(const device_t *info) +{ + mach64_t *mach64 = mach64_common_init(info); + svga_t *svga = &mach64->svga; + + svga->dac_hwcursor_draw = NULL; + + svga->hwcursor.cur_ysize = 64; + svga->hwcursor.cur_xsize = 64; + + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_mach64_pci); + + mach64->pci = 1; + mach64->vlb = 0; + mach64->pci_id = 0x5655; + mach64->config_chip_id = 0x9A005655; + mach64->dac_cntl = 1 << 16; /*Internal 24-bit DAC*/ + mach64->config_stat0 = 4; + mach64->use_block_decoded_io = 4; + + mem_mapping_disable(&mach64->bios_rom.mapping); + + svga->vblank_start = mach64_vblank_start; + svga->adv_flags |= FLAG_PANNING_ATI; + + *reset_state[monitor_index_global] = *mach64; return mach64; } @@ -5101,17 +5631,25 @@ mach64_close(void *priv) { mach64_t *mach64 = (mach64_t *) priv; +#ifdef DMA_BM + mach64->dma.state = 0; +#endif mach64->thread_run = 0; thread_set_event(mach64->wake_fifo_thread); thread_wait(mach64->fifo_thread); thread_destroy_event(mach64->fifo_not_full_event); thread_destroy_event(mach64->wake_fifo_thread); +#ifdef DMA_BM + thread_close_mutex(mach64->dma.lock); +#endif svga_close(&mach64->svga); ddc_close(mach64->ddc); i2c_gpio_close(mach64->i2c); + i2c_gpio_close(mach64->i2c_tv); + free(reset_state[mach64->svga.monitor_index]); free(mach64); } @@ -5269,3 +5807,17 @@ const device_t mach64vt2_device = { .force_redraw = mach64_force_redraw, .config = mach64vt2_config }; + +const device_t mach64vt3_onboard_device = { + .name = "ATI Mach64VT3 (On-Board)", + .internal_name = "mach64vt3_onboard", + .flags = DEVICE_PCI, + .local = MACH64_VT3 | (1 << 19), + .init = mach64vt3_onboard_init, + .close = mach64_close, + .reset = mach64_reset, + .available = NULL, + .speed_changed = mach64_speed_changed, + .force_redraw = mach64_force_redraw, + .config = NULL +}; diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index b9092881b60..81abadd5666 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -2371,7 +2371,7 @@ mach_out(uint16_t addr, uint8_t val, void *priv) svga->write_bank = mach->bank_w << 16; if (mach->index == 0xbe) { - if ((old ^ val) & 0x10) { + if ((old ^ val) & 0x13) { mach_log("ATI BE bit 4.\n"); svga_recalctimings(svga); } @@ -3320,30 +3320,30 @@ mach_recalctimings(svga_t *svga) } else { dev->mode = VGA_MODE; if (!svga->scrblank && svga->attr_palette_enable) { - mach_log("GDCREG5=%02x, ATTR10=%02x, ATI B0 bit 5=%02x, ON=%d.\n", - svga->gdcreg[5] & 0x60, svga->attrregs[0x10] & 0x40, mach->regs[0xb0] & 0x20, dev->on); + mach_log("GDCREG5=%02x, ATTR10=%02x, ATI B0 bit 5=%02x, ON=%d, char_width=%d, seqreg1 bit 3=%x, clk_sel=%02x.\n", + svga->gdcreg[5] & 0x60, svga->attrregs[0x10] & 0x40, mach->regs[0xb0] & 0x20, dev->on, svga->char_width, svga->seqregs[1] & 0x08, clock_sel); + if (ATI_MACH32) + svga->clock = (cpuclock * (double) (1ULL << 32)) / svga->getclock(clock_sel, svga->clock_gen); + else + svga->clock = (cpuclock * (double) (1ULL << 32)) / svga->getclock(clock_sel ^ 0x08, svga->clock_gen); + + switch ((mach->regs[0xb8] >> 6) & 3) { + case 1: + svga->clock *= 2.0; + break; + case 2: + svga->clock *= 3.0; + break; + case 3: + svga->clock *= 4.0; + break; + default: + break; + } mach_log("VGA clock sel=%02x, divide reg=%02x, miscout bits2-3=%x, machregbe bit4=%02x, machregb9 bit1=%02x, charwidth=%d, htotal=%02x, hdisptime=%02x, seqregs1 bit 3=%02x.\n", clock_sel, (mach->regs[0xb8] >> 6) & 3, svga->miscout & 0x0c, mach->regs[0xbe] & 0x10, mach->regs[0xb9] & 0x02, svga->char_width, svga->htotal, svga->hdisp_time, svga->seqregs[1] & 8); if ((svga->gdcreg[6] & 0x01) || (svga->attrregs[0x10] & 0x01)) { if ((svga->gdcreg[5] & 0x40) || (svga->attrregs[0x10] & 0x40) || (mach->regs[0xb0] & 0x20)) { - if (ATI_MACH32) - svga->clock = (cpuclock * (double) (1ULL << 32)) / svga->getclock(clock_sel, svga->clock_gen); - else - svga->clock = (cpuclock * (double) (1ULL << 32)) / svga->getclock(clock_sel ^ 0x08, svga->clock_gen); - - switch ((mach->regs[0xb8] >> 6) & 3) { - case 1: - svga->clock *= 2.0; - break; - case 2: - svga->clock *= 3.0; - break; - case 3: - svga->clock *= 4.0; - break; - default: - break; - } svga->map8 = svga->pallook; mach_log("Lowres=%x, seqreg[1]bit3=%x.\n", svga->lowres, svga->seqregs[1] & 8); if (svga->lowres) @@ -3356,26 +3356,6 @@ mach_recalctimings(svga_t *svga) } } } - } else { - if (ATI_MACH32) - svga->clock = (cpuclock * (double) (1ULL << 32)) / svga->getclock(clock_sel, svga->clock_gen); - else - svga->clock = (cpuclock * (double) (1ULL << 32)) / svga->getclock(clock_sel ^ 0x08, svga->clock_gen); - - switch ((mach->regs[0xb8] >> 6) & 3) { - case 0: - default: - break; - case 1: - svga->clock *= 2.0; - break; - case 2: - svga->clock *= 3.0; - break; - case 3: - svga->clock *= 4.0; - break; - } } } } diff --git a/src/video/vid_cga.c b/src/video/vid_cga.c index 3bedf53a410..65c85480a4b 100644 --- a/src/video/vid_cga.c +++ b/src/video/vid_cga.c @@ -239,9 +239,13 @@ cga_recalctimings(cga_t *cga) if (cga->cgamode & CGA_MODE_FLAG_HIGHRES) { disptime = (double) (cga->crtc[CGA_CRTC_HTOTAL] + 1); _dispontime = (double) cga->crtc[CGA_CRTC_HDISP]; + if (_dispontime >= disptime) + _dispontime = disptime - 1; } else { disptime = (double) ((cga->crtc[CGA_CRTC_HTOTAL] + 1) << 1); _dispontime = (double) (cga->crtc[CGA_CRTC_HDISP] << 1); + if (_dispontime >= disptime) + _dispontime = disptime - 2; } _dispofftime = disptime - _dispontime; _dispontime = _dispontime * CGACONST; @@ -782,13 +786,13 @@ cga_standalone_init(UNUSED(const device_t *info)) switch(device_get_config_int("font")) { case 0: - loadfont(FONT_IBM_MDA_437_PATH, 0); + video_load_font(FONT_IBM_MDA_437_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; case 1: - loadfont(FONT_IBM_MDA_437_NORDIC_PATH, 0); + video_load_font(FONT_IBM_MDA_437_NORDIC_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; case 4: - loadfont(FONT_TULIP_DGA_PATH, 0); + video_load_font(FONT_TULIP_DGA_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; } @@ -802,7 +806,7 @@ cga_pravetz_init(const device_t *info) { cga_t *cga = cga_standalone_init(info); - loadfont("roms/video/cga/PRAVETZ-VDC2.BIN", 10); + video_load_font("roms/video/cga/PRAVETZ-VDC2.BIN", FONT_FORMAT_PRAVETZ, LOAD_FONT_NO_OFFSET); io_removehandler(0x03dd, 0x0001, cga_in, NULL, NULL, cga_out, NULL, NULL, cga); io_sethandler(0x03dd, 0x0001, cga_pravetz_in, NULL, NULL, cga_pravetz_out, NULL, NULL, cga); diff --git a/src/video/vid_cga_ncr.c b/src/video/vid_cga_ncr.c index 6b0f15f6545..cda38036bb4 100644 --- a/src/video/vid_cga_ncr.c +++ b/src/video/vid_cga_ncr.c @@ -562,7 +562,7 @@ nga_init(UNUSED(const device_t *info)) charset = device_get_config_int("charset"); - loadfont_ex("roms/video/nga/ncr_nga_35122.bin", 1, 4096 * charset); + video_load_font("roms/video/nga/ncr_nga_35122.bin", 1, 4096 * charset); nga->cga.composite = 0; nga->cga.snow_enabled = device_get_config_int("snow_enabled"); diff --git a/src/video/vid_cga_olivetti.c b/src/video/vid_cga_olivetti.c index 4cb845684fc..0279621a181 100644 --- a/src/video/vid_cga_olivetti.c +++ b/src/video/vid_cga_olivetti.c @@ -592,7 +592,7 @@ ogc_init(UNUSED(const device_t *info)) memset(ogc, 0x00, sizeof(ogc_t)); video_inform(VIDEO_FLAG_TYPE_CGA, &timing_ogc); - loadfont("roms/video/ogc/ogc graphics board go380 258 pqbq.bin", 1); + video_load_font("roms/video/ogc/ogc graphics board go380 258 pqbq.bin", FONT_FORMAT_PC200, LOAD_FONT_NO_OFFSET); /* FIXME: composite is not working yet */ #if 0 @@ -664,7 +664,7 @@ const device_config_t ogc_m24_config[] = { }; const device_t ogc_m24_device = { - .name = "Olivetti M21/M24/M28 (GO317/318/380/709) video card", + .name = "Olivetti M21/M24/M28 (GO317/318/380/709)", .internal_name = "ogc_m24", .flags = DEVICE_ISA, .local = 0, diff --git a/src/video/vid_cga_quadcolor.c b/src/video/vid_cga_quadcolor.c index 4159dc2c12a..c5c3d34562a 100644 --- a/src/video/vid_cga_quadcolor.c +++ b/src/video/vid_cga_quadcolor.c @@ -828,13 +828,13 @@ quadcolor_standalone_init(UNUSED(const device_t *info)) switch(device_get_config_int("font")) { case 0: - loadfont(FONT_IBM_MDA_437_PATH, 0); + video_load_font(FONT_IBM_MDA_437_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; case 1: - loadfont(FONT_IBM_MDA_437_NORDIC_PATH, 0); + video_load_font(FONT_IBM_MDA_437_NORDIC_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; case 4: - loadfont(FONT_TULIP_DGA_PATH, 0); + video_load_font(FONT_TULIP_DGA_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; } diff --git a/src/video/vid_cga_toshiba_t1000.c b/src/video/vid_cga_toshiba_t1000.c index 894d28a567a..2a16a7d0eb3 100644 --- a/src/video/vid_cga_toshiba_t1000.c +++ b/src/video/vid_cga_toshiba_t1000.c @@ -650,7 +650,7 @@ static void * t1000_init(UNUSED(const device_t *info)) { t1000_t *t1000 = calloc(1, sizeof(t1000_t)); - loadfont("roms/machines/t1000/t1000font.bin", 8); + video_load_font("roms/machines/t1000/t1000font.bin", FONT_FORMAT_PC1512_T1000, LOAD_FONT_NO_OFFSET); cga_init(&t1000->cga); video_inform(VIDEO_FLAG_TYPE_CGA, &timing_t1000); diff --git a/src/video/vid_cga_toshiba_t3100e.c b/src/video/vid_cga_toshiba_t3100e.c index 25f0792049d..d8344426bdf 100644 --- a/src/video/vid_cga_toshiba_t3100e.c +++ b/src/video/vid_cga_toshiba_t3100e.c @@ -654,7 +654,7 @@ void * t3100e_init(UNUSED(const device_t *info)) { t3100e_t *t3100e = calloc(1, sizeof(t3100e_t)); - loadfont("roms/machines/t3100e/t3100e_font.bin", 5); + video_load_font("roms/machines/t3100e/t3100e_font.bin", FONT_FORMAT_TOSHIBA_3100E, LOAD_FONT_NO_OFFSET); cga_init(&t3100e->cga); video_inform(VIDEO_FLAG_TYPE_CGA, &timing_t3100e); diff --git a/src/video/vid_cga_v6355.c b/src/video/vid_cga_v6355.c index 1ddc1f2cd6e..f259f627794 100644 --- a/src/video/vid_cga_v6355.c +++ b/src/video/vid_cga_v6355.c @@ -924,13 +924,13 @@ v6355_standalone_init(const device_t *info) { switch(device_get_config_int("font")) { case 0: - loadfont(FONT_IBM_MDA_437_PATH, 0); + video_load_font(FONT_IBM_MDA_437_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; case 1: - loadfont(FONT_IBM_MDA_437_NORDIC_PATH, 0); + video_load_font(FONT_IBM_MDA_437_NORDIC_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; case 4: - loadfont(FONT_TULIP_DGA_PATH, 0); + video_load_font(FONT_TULIP_DGA_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; } diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 95f9e7bf6ca..4161e223e82 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -768,6 +768,8 @@ gd54xx_out(uint16_t addr, uint8_t val, void *priv) svga->seqregs[6] = 0x0f; if (svga->crtc[0x27] < CIRRUS_ID_CLGD5429) gd54xx->unlocked = (svga->seqregs[6] == 0x12); + else + gd54xx->unlocked = 1; break; case 0x08: if (gd54xx->i2c) @@ -1643,6 +1645,10 @@ gd54xx_in(uint16_t addr, void *priv) case 0x24: /*Attribute controller toggle readback (R)*/ ret = svga->attrff << 7; break; + case 0x25: /* Part ID */ + if (svga->crtc[0x27] == CIRRUS_ID_CLGD5434) + ret = 0xb0; + break; case 0x26: /*Attribute controller index readback (R)*/ ret = svga->attraddr & 0x3f; break; diff --git a/src/video/vid_et4000.c b/src/video/vid_et4000.c index 937623689a6..608cc9601d5 100644 --- a/src/video/vid_et4000.c +++ b/src/video/vid_et4000.c @@ -57,7 +57,7 @@ #define ET4000_TYPE_ISA 1 /* ISA ET4000AX */ #define ET4000_TYPE_MCA 2 /* MCA ET4000AX */ #define ET4000_TYPE_KOREAN 3 /* Korean ET4000 */ -#define ET4000_TYPE_TRIGEM 4 /* Trigem 286M ET4000 */ +#define ET4000_TYPE_TRIGEM 4 /* TriGem 286M ET4000 */ #define ET4000_TYPE_KASAN 5 /* Kasan ET4000 */ #define BIOS_ROM_PATH "roms/video/et4000/ET4000.BIN" @@ -829,7 +829,7 @@ et4000_init(const device_t *info) break; case ET4000_TYPE_KOREAN: /* Korean ET4000 */ - case ET4000_TYPE_TRIGEM: /* Trigem 286M ET4000 */ + case ET4000_TYPE_TRIGEM: /* TriGem 286M ET4000 */ dev->vram_size = device_get_config_int("memory") << 10; dev->port_22cb_val = 0x60; dev->port_32cb_val = 0; @@ -850,7 +850,7 @@ et4000_init(const device_t *info) et4000k_in, NULL, NULL, et4000k_out, NULL, NULL, dev); io_sethandler(0x32cb, 1, et4000k_in, NULL, NULL, et4000k_out, NULL, NULL, dev); - loadfont(KOREAN_FONT_ROM_PATH, 6); + video_load_font(KOREAN_FONT_ROM_PATH, FONT_FORMAT_KSC6501, LOAD_FONT_NO_OFFSET); fn = KOREAN_BIOS_ROM_PATH; break; @@ -884,7 +884,7 @@ et4000_init(const device_t *info) et4000_kasan_in, NULL, NULL, et4000_kasan_out, NULL, NULL, dev); io_sethandler(0x0258, 2, et4000_kasan_in, NULL, NULL, et4000_kasan_out, NULL, NULL, dev); - loadfont(KASAN_FONT_ROM_PATH, 6); + video_load_font(KASAN_FONT_ROM_PATH, FONT_FORMAT_KSC6501, LOAD_FONT_NO_OFFSET); fn = KASAN_BIOS_ROM_PATH; break; @@ -1133,7 +1133,7 @@ const device_t et4000_mca_device = { }; const device_t et4000k_isa_device = { - .name = "Trigem Korean VGA (Tseng Labs ET4000AX Korean)", + .name = "TriGem Korean VGA (Tseng Labs ET4000AX Korean)", .internal_name = "tgkorvga", .flags = DEVICE_ISA, .local = ET4000_TYPE_KOREAN, @@ -1147,7 +1147,7 @@ const device_t et4000k_isa_device = { }; const device_t et4000k_tg286_isa_device = { - .name = "Trigem Korean VGA (Trigem 286M)", + .name = "TriGem Korean VGA (TriGem 286M)", .internal_name = "et4000k_tg286_isa", .flags = DEVICE_ISA, .local = ET4000_TYPE_TRIGEM, diff --git a/src/video/vid_genius.c b/src/video/vid_genius.c index 472217d3043..0289e1104ac 100644 --- a/src/video/vid_genius.c +++ b/src/video/vid_genius.c @@ -329,12 +329,13 @@ genius_recalctimings(genius_t *genius) double disptime; double _dispontime; double _dispofftime; + double crtcconst = (cpuclock / 53216000.0 * (double) (1ULL << 32)) * 9.0; - disptime = 0x31; - _dispontime = 0x28; + disptime = 0x62; + _dispontime = 0x50; _dispofftime = disptime - _dispontime; - _dispontime *= MDACONST; - _dispofftime *= MDACONST; + _dispontime *= crtcconst; + _dispofftime *= crtcconst; genius->dispontime = (uint64_t) (_dispontime); genius->dispofftime = (uint64_t) (_dispofftime); } @@ -744,7 +745,7 @@ genius_init(UNUSED(const device_t *info)) /* 160k video RAM */ genius->vram = malloc(0x28000); - loadfont(BIOS_ROM_PATH, 4); + video_load_font(BIOS_ROM_PATH, FONT_FORMAT_MDSI_GENIUS, LOAD_FONT_NO_OFFSET); timer_add(&genius->timer, genius_poll, genius, 1); diff --git a/src/video/vid_hercules.c b/src/video/vid_hercules.c index 758b041af31..a53ea9871a0 100644 --- a/src/video/vid_hercules.c +++ b/src/video/vid_hercules.c @@ -542,19 +542,19 @@ hercules_init(UNUSED(const device_t *info)) switch(device_get_config_int("font")) { case 0: - loadfont(FONT_IBM_MDA_437_PATH, 0); + video_load_font(FONT_IBM_MDA_437_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; case 1: - loadfont(FONT_IBM_MDA_437_NORDIC_PATH, 0); + video_load_font(FONT_IBM_MDA_437_NORDIC_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; case 2: - loadfont(FONT_KAM_PATH, 0); + video_load_font(FONT_KAM_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; case 3: - loadfont(FONT_KAMCL16_PATH, 0); + video_load_font(FONT_KAMCL16_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; case 4: - loadfont(FONT_TULIP_DGA_PATH, 0); + video_load_font(FONT_TULIP_DGA_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; } diff --git a/src/video/vid_hercules_incolor.c b/src/video/vid_hercules_incolor.c index b9be0765e99..e6acb9bbb80 100644 --- a/src/video/vid_hercules_incolor.c +++ b/src/video/vid_hercules_incolor.c @@ -994,19 +994,19 @@ incolor_init(UNUSED(const device_t *info)) switch(device_get_config_int("font")) { case 0: - loadfont(FONT_IBM_MDA_437_PATH, 0); + video_load_font(FONT_IBM_MDA_437_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; case 1: - loadfont(FONT_IBM_MDA_437_NORDIC_PATH, 0); + video_load_font(FONT_IBM_MDA_437_NORDIC_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; case 2: - loadfont(FONT_KAM_PATH, 0); + video_load_font(FONT_KAM_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; case 3: - loadfont(FONT_KAMCL16_PATH, 0); + video_load_font(FONT_KAMCL16_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; case 4: - loadfont(FONT_TULIP_DGA_PATH, 0); + video_load_font(FONT_TULIP_DGA_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; } diff --git a/src/video/vid_hercules_plus.c b/src/video/vid_hercules_plus.c index 25b44ad70ee..f6eb2e9fb6d 100644 --- a/src/video/vid_hercules_plus.c +++ b/src/video/vid_hercules_plus.c @@ -631,19 +631,19 @@ herculesplus_init(UNUSED(const device_t *info)) switch(device_get_config_int("font")) { case 0: - loadfont(FONT_IBM_MDA_437_PATH, 0); + video_load_font(FONT_IBM_MDA_437_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; case 1: - loadfont(FONT_IBM_MDA_437_NORDIC_PATH, 0); + video_load_font(FONT_IBM_MDA_437_NORDIC_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; case 2: - loadfont(FONT_KAM_PATH, 0); + video_load_font(FONT_KAM_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; case 3: - loadfont(FONT_KAMCL16_PATH, 0); + video_load_font(FONT_KAMCL16_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; case 4: - loadfont(FONT_TULIP_DGA_PATH, 0); + video_load_font(FONT_TULIP_DGA_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; } diff --git a/src/video/vid_ht216.c b/src/video/vid_ht216.c index 42a3376748d..45f8766ef30 100644 --- a/src/video/vid_ht216.c +++ b/src/video/vid_ht216.c @@ -1917,7 +1917,7 @@ const device_t v7_vga_1024i_device = { }; const device_t ht216_32_pb410a_device = { - .name = "Headland HT216-32 (Packard Bell PB410A)", + .name = "Headland HT216-32 On-Board (Packard Bell PB410A)", .internal_name = "ht216_32_pb410a", .flags = DEVICE_VLB, .local = 0x7861, /*HT216-32*/ diff --git a/src/video/vid_im1024.c b/src/video/vid_im1024.c index 1ade8badbcc..b16855229a6 100644 --- a/src/video/vid_im1024.c +++ b/src/video/vid_im1024.c @@ -1036,7 +1036,7 @@ im1024_init(UNUSED(const device_t *info)) dev = (im1024_t *) malloc(sizeof(im1024_t)); memset(dev, 0x00, sizeof(im1024_t)); - loadfont(BIOS_ROM_PATH, 9); + video_load_font(BIOS_ROM_PATH, FONT_FORMAT_IM1024, LOAD_FONT_NO_OFFSET); dev->fifo_len = 4096; dev->fifo = (uint8_t *) malloc(dev->fifo_len); diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index d3c80670870..5f38df23ca5 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -686,7 +686,7 @@ readfontxtbl(fontx_tbl *table, int size, FILE *fp) } static int -LoadFontxFile(const char *fn, void *priv) +jega_load_font(const char *fn, void *priv) { fontx_h fhead; fontx_tbl *ftbl; @@ -793,7 +793,7 @@ jega_standalone_init(const device_t *info) rom_init(&jega->bios_rom, JEGA_PATH_BIOS, 0xc0000, 0x8000, 0x7fff, 0, 0); memset(&jega->jfont_dbcs_16, 0, DBCS16_FILESIZE); - LoadFontxFile(JEGA_PATH_FONTDBCS, jega); + jega_load_font(JEGA_PATH_FONTDBCS, jega); jega_commoninit(info, jega, 0); @@ -807,7 +807,7 @@ jvga_standalone_init(const device_t *info) rom_init(&jega->bios_rom, JVGA_PATH_BIOS, 0xc0000, 0x8000, 0x7fff, 0, 0); memset(&jega->jfont_dbcs_16, 0, DBCS16_FILESIZE); - LoadFontxFile(JVGA_PATH_FONTDBCS, jega); + jega_load_font(JVGA_PATH_FONTDBCS, jega); jega_commoninit(info, jega, 1); @@ -1024,7 +1024,7 @@ if386jega_init(const device_t *info) rom_init(&jega->bios_rom, IF386_PATH_VBIOS, 0xc0000, 0x8000, 0x7fff, 0, 0); memset(&jega->jfont_dbcs_16, 0, DBCS16_FILESIZE); - LoadFontxFile(JEGA_PATH_FONTDBCS, jega); + jega_load_font(JEGA_PATH_FONTDBCS, jega); jega_commoninit(info, jega, 0); @@ -1042,7 +1042,7 @@ if386jega_available(void) } const device_t if386jega_device = { - .name = "JEGA (if386AX)", + .name = "JEGA On-Board (OKI if386AX30L)", .internal_name = "if386jega", .flags = DEVICE_ISA, .local = 0, diff --git a/src/video/vid_mda.c b/src/video/vid_mda.c index f530419f2d8..574e315506c 100644 --- a/src/video/vid_mda.c +++ b/src/video/vid_mda.c @@ -414,27 +414,27 @@ mda_init(mda_t *mda) void * mda_standalone_init(UNUSED(const device_t *info)) { - mda_t *mda = malloc(sizeof(mda_t)); - memset(mda, 0, sizeof(mda_t)); + mda_t *mda = calloc(1, sizeof(mda_t)); + video_inform(VIDEO_FLAG_TYPE_MDA, &timing_mda); - mda->vram = malloc(0x1000); + mda->vram = malloc(MDA_VRAM); switch (device_get_config_int("font")) { case 0: - loadfont(FONT_IBM_MDA_437_PATH, 0); + video_load_font(FONT_IBM_MDA_437_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; case 1: - loadfont(FONT_IBM_MDA_437_NORDIC_PATH, 0); + video_load_font(FONT_IBM_MDA_437_NORDIC_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; case 2: - loadfont(FONT_KAM_PATH, 0); + video_load_font(FONT_KAM_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; case 3: - loadfont(FONT_KAMCL16_PATH, 0); + video_load_font(FONT_KAMCL16_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; case 4: - loadfont(FONT_TULIP_DGA_PATH, 0); + video_load_font(FONT_TULIP_DGA_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); break; } diff --git a/src/video/vid_mga.c b/src/video/vid_mga.c index 68de89767f5..07b0869f797 100644 --- a/src/video/vid_mga.c +++ b/src/video/vid_mga.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include <86box/86box.h> #include <86box/io.h> @@ -5149,7 +5150,7 @@ static uint16_t texture_texel_fetch(mystique_t *mystique, int *tex_r, int *tex_g *atransp = 0; break; case TEXCTL_TEXFORMAT_TW15: - src = ((uint16_t *) svga->vram)[((mystique->dwgreg.texorg >> 1) + (t * tex_pitch) + s) & mystique->vram_mask_w]; + src = *(uint16_t*)((&svga->vram[(mystique->dwgreg.texorg + ((t * tex_pitch) + s) * 2) & mystique->vram_mask])); *tex_r = ((src >> 10) & 0x1f) << 3; *tex_g = ((src >> 5) & 0x1f) << 3; *tex_b = (src & 0x1f) << 3; @@ -5159,7 +5160,7 @@ static uint16_t texture_texel_fetch(mystique_t *mystique, int *tex_r, int *tex_g *atransp = 0; break; case TEXCTL_TEXFORMAT_TW12: - src = ((uint16_t *) svga->vram)[((mystique->dwgreg.texorg >> 1) + (t * tex_pitch) + s) & mystique->vram_mask_w]; + src = *(uint16_t*)((&svga->vram[(mystique->dwgreg.texorg + ((t * tex_pitch) + s) * 2) & mystique->vram_mask])); *tex_r = ((src >> 8) & 0xf) << 4; *tex_g = ((src >> 4) & 0xf) << 4; *tex_b = (src & 0xf) << 4; @@ -5173,7 +5174,7 @@ static uint16_t texture_texel_fetch(mystique_t *mystique, int *tex_r, int *tex_g } break; case TEXCTL_TEXFORMAT_TW16: - src = ((uint16_t *) svga->vram)[((mystique->dwgreg.texorg >> 1) + (t * tex_pitch) + s) & mystique->vram_mask_w]; + src = *(uint16_t*)((&svga->vram[(mystique->dwgreg.texorg + ((t * tex_pitch) + s) * 2) & mystique->vram_mask])); *tex_r = (src >> 11) << 3; *tex_g = ((src >> 5) & 0x3f) << 2; *tex_b = (src & 0x1f) << 3; @@ -5190,6 +5191,40 @@ static double lerp(double v0, double v1, double t) { return (1. - t) * v0 + t * v1; } +// Taken from GZDoom. +static inline double +FixedToFloat(int fixed) +{ + return fixed * (1.0 / (1 << 16)); +} + +static inline void +persp_correct(mystique_t* mystique, int* s, int* t, int* q, double* s_frac, double* t_frac) +{ + const int s_shift = 20 - (mystique->dwgreg.texwidth & TEXWIDTH_TW_MASK); + const int t_shift = 20 - (mystique->dwgreg.texheight & TEXHEIGHT_TH_MASK); + double s_d = ((*s) >> s_shift); + double t_d = ((*t) >> t_shift); + double q_d = FixedToFloat(*q); + + double throwaway1 = 0; + double throwaway2 = 0; + if (q_d == 0.0) + q_d = INFINITY; + + s_d *= 1. / q_d; + t_d *= 1. / q_d; + + *s_frac = fabs(modf(s_d, &throwaway1)); + *t_frac = fabs(modf(s_d, &throwaway2)); + + (void)throwaway1; + (void)throwaway2; + + *s = s_d; + *t = t_d; +} + static int texture_read(mystique_t *mystique, int *tex_r, int *tex_g, int *tex_b, int *atransp, int *tex_a) { @@ -5223,14 +5258,11 @@ texture_read(mystique_t *mystique, int *tex_r, int *tex_g, int *tex_b, int *atra s_frac = (((int32_t) mystique->dwgreg.tmr[6]) & ((1 << s_shift) - 1)) / (double)(1 << s_shift); t_frac = (((int32_t) mystique->dwgreg.tmr[7]) & ((1 << t_shift) - 1)) / (double)(1 << t_shift); } else { - const int s_shift = (20 + 16) - (mystique->dwgreg.texwidth & TEXWIDTH_TW_MASK); - const int t_shift = (20 + 16) - (mystique->dwgreg.texheight & TEXHEIGHT_TH_MASK); - int64_t q = mystique->dwgreg.tmr[8] ? (0x100000000LL / (int64_t) (int32_t) mystique->dwgreg.tmr[8]) : 0; - - s = ((int64_t) (int32_t) mystique->dwgreg.tmr[6] * q) >> s_shift; - t = ((int64_t) (int32_t) mystique->dwgreg.tmr[7] * q) >> t_shift; - s_frac = (((int64_t) (int32_t) mystique->dwgreg.tmr[6] * q) & ((1 << s_shift) - 1)) / (double)(1 << s_shift); - t_frac = (((int64_t) (int32_t) mystique->dwgreg.tmr[7] * q) & ((1 << t_shift) - 1)) / (double)(1 << t_shift); + int q = (int32_t)mystique->dwgreg.tmr[8]; + s = (int32_t) mystique->dwgreg.tmr[6]; + t = (int32_t) mystique->dwgreg.tmr[7]; + + persp_correct(mystique, &s, &t, &q, &s_frac, &t_frac); } if (mystique->dwgreg.texctl & TEXCTL_CLAMPU) { diff --git a/src/video/vid_oak_oti.c b/src/video/vid_oak_oti.c index d8e3a89e462..e2ef1fbbbf4 100644 --- a/src/video/vid_oak_oti.c +++ b/src/video/vid_oak_oti.c @@ -702,7 +702,7 @@ const device_t oti037c_device = { }; const device_t oti037_pbl300sx_device = { - .name = "Oak OTI-037 (Packard Bell Legend 300SX)", + .name = "Oak OTI-037 On-Board (Packard Bell PB300/PB320)", .internal_name = "oti037_pbl300sx", .flags = DEVICE_ISA, .local = 1, @@ -730,7 +730,7 @@ const device_t oti067_device = { }; const device_t oti067_ama932j_device = { - .name = "Oak OTI-067 (AMA-932J)", + .name = "Oak OTI-067 On-Board (Arche AMA-932J)", .internal_name = "oti067_ama932j", .flags = DEVICE_ISA, .local = 3, @@ -744,7 +744,7 @@ const device_t oti067_ama932j_device = { }; const device_t oti067_m300_device = { - .name = "Oak OTI-067 (Olivetti M300-08/15)", + .name = "Oak OTI-067 On-Board (Olivetti M300-08/15)", .internal_name = "oti067_m300", .flags = DEVICE_ISA, .local = 4, @@ -772,7 +772,7 @@ const device_t oti077_device = { }; const device_t oti077_acer100t_device = { - .name = "Oak OTI-077 (Acer 100T)", + .name = "Oak OTI-077 On-Board (Acer 100T)", .internal_name = "oti077_acer100t", .flags = DEVICE_ISA, .local = 6, @@ -785,7 +785,7 @@ const device_t oti077_acer100t_device = { .config = oti077_acer100t_config }; const device_t oti077_pcs44c_device = { - .name = "Oak OTI-077 (Olivetti PCS 44/C)", + .name = "Oak OTI-077 On-Board (Olivetti PCS 44/C)", .internal_name = "oti077_pcs44c", .flags = DEVICE_ISA, .local = 7, diff --git a/src/video/vid_paradise.c b/src/video/vid_paradise.c index 4d8442d7a66..8d178dbd5f3 100644 --- a/src/video/vid_paradise.c +++ b/src/video/vid_paradise.c @@ -964,7 +964,7 @@ paradise_force_redraw(void *priv) } const device_t paradise_pvga1a_pc2086_device = { - .name = "Paradise PVGA1A (Amstrad PC2086)", + .name = "Paradise PVGA1A On-Board (Amstrad PC2086)", .internal_name = "pvga1a_pc2086", .flags = 0, .local = PVGA1A, @@ -978,7 +978,7 @@ const device_t paradise_pvga1a_pc2086_device = { }; const device_t paradise_pvga1a_pc3086_device = { - .name = "Paradise PVGA1A (Amstrad PC3086)", + .name = "Paradise PVGA1A On-Board (Amstrad PC3086)", .internal_name = "pvga1a_pc3086", .flags = 0, .local = PVGA1A, @@ -1013,7 +1013,7 @@ static const device_config_t paradise_pvga1a_config[] = { }; const device_t paradise_pvga1a_ncr3302_device = { - .name = "Paradise PVGA1A (NCR 3302)", + .name = "Paradise PVGA1A On-Board (NCR 3302)", .internal_name = "pvga1a_ncr3302", .flags = 0, .local = PVGA1A, @@ -1041,7 +1041,7 @@ const device_t paradise_pvga1a_device = { }; const device_t paradise_wd90c11_megapc_device = { - .name = "Paradise WD90C11 (Amstrad MegaPC)", + .name = "Paradise WD90C11 On-Board (Amstrad MegaPC)", .internal_name = "wd90c11_megapc", .flags = 0, .local = WD90C11, diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index a97d2aa84fb..3df73f92cea 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -3149,7 +3149,7 @@ da2_poll(void *priv) } static void -da2_loadfont(char *fname, void *priv) +da2_video_load_font(char *fname, void *priv) { da2_t *da2 = (da2_t *) priv; uint8_t buf; @@ -3267,10 +3267,10 @@ da2_init(UNUSED(const device_t *info)) da2->mmio.font = malloc(DA2_FONTROM_SIZE); switch (da2->mmio.charset) { case DA2_DCONFIG_CHARSET_HANT: - da2_loadfont(DA2_FONTROM_PATH_HANT, da2); + da2_video_load_font(DA2_FONTROM_PATH_HANT, da2); break; case DA2_DCONFIG_CHARSET_JPAN: - da2_loadfont(DA2_FONTROM_PATH_JPAN, da2); + da2_video_load_font(DA2_FONTROM_PATH_JPAN, da2); /* Add magic code for OS/2 J1.3. This disables BitBlt's text drawing function. */ da2->mmio.font[0x1AFFE] = 0x80; da2->mmio.font[0x1AFFF] = 0x01; diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index cc3841750e4..101d3ae8bf5 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -354,7 +354,7 @@ typedef struct s3_t { int input; int len, start; int odf, idf, yuv; - atomic_int busy; + ATOMIC_INT busy; } videoengine; struct @@ -390,7 +390,7 @@ typedef struct s3_t { } streams; fifo_entry_t fifo[FIFO_SIZE]; - atomic_int fifo_read_idx, fifo_write_idx; + ATOMIC_INT fifo_read_idx, fifo_write_idx; uint8_t fifo_thread_run; @@ -398,7 +398,7 @@ typedef struct s3_t { event_t *wake_fifo_thread; event_t *fifo_not_full_event; - atomic_int blitter_busy; + ATOMIC_INT blitter_busy; uint64_t blitter_time; uint64_t status_time; @@ -410,7 +410,7 @@ typedef struct s3_t { int translate; int enable_8514; int color_16bit; - atomic_int busy, force_busy; + ATOMIC_INT busy, force_busy; bool color_key_enabled; @@ -2727,7 +2727,7 @@ s3_trio64v_colorkey(s3_t* s3, uint32_t x, uint32_t y) uint8_t shift = ((s3->streams.chroma_ctrl >> 24) & 7) ^ 7; bool is15bpp = false; - uint32_t base_addr = svga->memaddr_latch; + uint32_t base_addr = svga->memaddr_latch << 2; uint32_t stride = s3->streams.pri_stride; if (!s3->color_key_enabled) @@ -3527,7 +3527,7 @@ s3_in(uint16_t addr, void *priv) } break; case 0x30: - return s3->id; /*Chip ID*/ + return ((svga->crtc[0x38] & 0xcc) != 0x48) ? 0xFF : s3->id; /*Chip ID*/ case 0x31: return (svga->crtc[0x31] & 0xcf) | ((s3->ma_ext & 3) << 4); case 0x35: diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index e9da4b412f8..abeba064ec2 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -24,6 +24,7 @@ #include #define HAVE_STDARG_H #include <86box/86box.h> +#include "cpu.h" #include <86box/io.h> #include <86box/timer.h> #include <86box/dma.h> @@ -290,9 +291,9 @@ typedef struct virge_t { s3d_t s3d_tri; s3d_t s3d_buffer[RB_SIZE]; - atomic_int s3d_read_idx; - atomic_int s3d_write_idx; - atomic_int s3d_busy; + ATOMIC_INT s3d_read_idx; + ATOMIC_INT s3d_write_idx; + ATOMIC_INT s3d_busy; struct { uint32_t pri_ctrl; @@ -332,15 +333,15 @@ typedef struct virge_t { } streams; fifo_entry_t fifo[FIFO_SIZE]; - atomic_int fifo_read_idx, fifo_write_idx; - atomic_int fifo_thread_run, render_thread_run; + ATOMIC_INT fifo_read_idx, fifo_write_idx; + ATOMIC_INT fifo_thread_run, render_thread_run; thread_t *fifo_thread; event_t *wake_fifo_thread; event_t *fifo_not_full_event; - atomic_int virge_busy; - atomic_uint irq_pending; + ATOMIC_INT virge_busy; + ATOMIC_UINT irq_pending; uint8_t subsys_stat; uint8_t subsys_cntl; @@ -751,7 +752,7 @@ s3_virge_in(uint16_t addr, void *priv) ret = virge->virge_rev; break; case 0x30: - ret = virge->virge_id; + ret = ((svga->crtc[0x38] & 0xcc) != 0x48) ? 0xFF : virge->virge_id; break; /*Chip ID*/ case 0x31: ret = (svga->crtc[0x31] & 0xcf) | ((virge->ma_ext & 3) << 4); @@ -828,6 +829,7 @@ s3_virge_recalctimings(svga_t *svga) if (virge->chip >= S3_TRIO3D2X) { svga_set_ramdac_type(svga, (svga->seqregs[0x1b] & 0x10) ? RAMDAC_8BIT : RAMDAC_6BIT); + svga->lut_map = !!(svga->seqregs[0x1b] & 0x8); } if (!svga->scrblank && svga->attr_palette_enable && (svga->crtc[0x43] & 0x80)) { /* TODO: In case of bug reports, disable 9-dots-wide character clocks in graphics modes. */ @@ -1190,6 +1192,9 @@ s3_virge_mmio_read(uint32_t addr, void *priv) virge_t *virge = (virge_t *) priv; uint8_t ret; + /* Add wait states for MMIO reads to prevent excessive polling */ + cycles -= virge->svga.monitor->mon_video_timing_read_b; + switch (addr & 0xffff) { case 0x8504: if (!virge->virge_busy) @@ -1241,6 +1246,9 @@ s3_virge_mmio_read_w(uint32_t addr, void *priv) virge_t *virge = (virge_t *) priv; uint16_t ret; + /* Add wait states for MMIO reads to prevent excessive polling */ + cycles -= virge->svga.monitor->mon_video_timing_read_w; + switch (addr & 0xfffe) { case 0x8504: ret = 0xc000; @@ -1274,6 +1282,9 @@ s3_virge_mmio_read_l(uint32_t addr, void *priv) virge_t *virge = (virge_t *) priv; uint32_t ret = 0xffffffff; + /* Add wait states for MMIO reads to prevent excessive polling */ + cycles -= virge->svga.monitor->mon_video_timing_read_l; + switch (addr & 0xfffc) { case 0x8180: ret = virge->streams.pri_ctrl; @@ -4842,7 +4853,7 @@ s3_virge_colorkey(virge_t* virge, uint32_t x, uint32_t y) uint8_t shift = ((virge->streams.chroma_ctrl >> 24) & 7) ^ 7; bool is15bpp = false; - uint32_t base_addr = svga->memaddr_latch; + uint32_t base_addr = svga->memaddr_latch << 2; uint32_t stride = (virge->chip < S3_VIRGEGX2) ? virge->streams.pri_stride : (svga->rowoffset << 3); bool color_key = false; @@ -5377,6 +5388,7 @@ s3_virge_init(const device_t *info) s3_virge_hwcursor_draw, s3_virge_overlay_draw); virge->svga.hwcursor.cur_ysize = 64; + virge->svga.conv_16to32 = tvp3026_conv_16to32; if (bios_fn != NULL) { if (virge->type == S3_VIRGE_GX2) diff --git a/src/video/vid_sigma.c b/src/video/vid_sigma.c index 4759bb7af09..d2c79b62e6e 100644 --- a/src/video/vid_sigma.c +++ b/src/video/vid_sigma.c @@ -794,7 +794,7 @@ sigma_init(UNUSED(const device_t *info)) sigma->enable_nmi = device_get_config_int("enable_nmi"); - loadfont(ROM_SIGMA_FONT, 7); + video_load_font(ROM_SIGMA_FONT, FONT_FORMAT_SIGMA, LOAD_FONT_NO_OFFSET); rom_init(&sigma->bios_rom, ROM_SIGMA_BIOS, bios_addr, 0x2000, 0x1FFF, 0, MEM_MAPPING_EXTERNAL); /* The BIOS ROM is overlaid by RAM, so remove its default mapping diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 43158adbb86..2409d12025c 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -1693,7 +1693,7 @@ svga_init(const device_t *info, svga_t *svga, void *priv, int memsize, svga->dispontime = 1000ULL << 32; svga->dispofftime = 1000ULL << 32; svga->bpp = 8; - svga->vram = calloc(memsize + 8, 1); + svga->vram = calloc(memsize + 4096, 1); svga->vram_max = memsize; svga->vram_display_mask = svga->vram_mask = memsize - 1; svga->decode_mask = 0x7fffff; diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index 25b3cd9463f..f266fbf8f55 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -91,7 +91,7 @@ svga_render_blank(svga_t *svga) line_width -= svga->x_add; } - if (((svga->hdisp + svga->scrollcache) > 0) && (line_width >= 0)) + if ((line_ptr != NULL) && ((svga->hdisp + svga->scrollcache) > 0) && (line_width >= 0)) memset(line_ptr, 0, line_width); } @@ -106,7 +106,7 @@ svga_render_overscan_left(svga_t *svga) uint32_t *line_ptr = svga->monitor->target_buffer->line[svga->displine + svga->y_add]; - if (svga->x_add >= 0) for (int i = 0; i < svga->x_add; i++) + if ((line_ptr != NULL) && (svga->x_add >= 0)) for (int i = 0; i < svga->x_add; i++) *line_ptr++ = svga->overscan_color; } @@ -121,10 +121,15 @@ svga_render_overscan_right(svga_t *svga) if (svga->scrblank || (svga->hdisp <= 0)) return; - uint32_t *line_ptr = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add + svga->hdisp]; + uint32_t *line_ptr = svga->monitor->target_buffer->line[svga->displine + svga->y_add]; right = overscan_x - svga->left_overscan; - for (int i = 0; i < right; i++) - *line_ptr++ = svga->overscan_color; + + if (line_ptr != NULL) { + line_ptr += svga->x_add + svga->hdisp; + + for (int i = 0; i < right; i++) + *line_ptr++ = svga->overscan_color; + } } void diff --git a/src/video/vid_table.c b/src/video/vid_table.c index cb7e794e879..368ee825467 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -73,6 +73,7 @@ video_cards[] = { { .device = &compaq_cga_2_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &cpqega_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &g2_gc205_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &genius_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &hercules_device, .flags = VIDEO_FLAG_TYPE_MDA }, { .device = &herculesplus_device, .flags = VIDEO_FLAG_TYPE_MDA }, { .device = &incolor_device, .flags = VIDEO_FLAG_TYPE_NONE }, @@ -85,7 +86,6 @@ video_cards[] = { { .device = &iskra_ega_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &jega_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &et4000_kasan_isa_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &genius_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &nga_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &nec_sv9000_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &ogc_device, .flags = VIDEO_FLAG_TYPE_NONE }, @@ -145,13 +145,6 @@ video_cards[] = { /* VLB */ { .device = &mach32_vlb_device, .flags = VIDEO_FLAG_TYPE_8514 }, { .device = &mach64gx_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &et4000w32_machspeed_vga_gui_2400s_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &et4000w32i_hercules_dynamite_pro_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &et4000w32p_videomagic_revb_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &et4000w32p_cardex_revc_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &et4000w32p_generic_revd_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &et4000w32p_cardex_revd_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &et4000w32p_diamond_revd_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &gd5424_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &gd5426_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &gd5428_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, @@ -160,6 +153,7 @@ video_cards[] = { { .device = &gd5430_diamond_speedstar_pro_se_a8_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &gd5430_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &gd5434_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &ht216_32_standalone_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &s3_elsa_winner1000_86c928_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &s3_metheus_86c928_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &s3_mirocrystal_8s_805_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, @@ -179,10 +173,20 @@ video_cards[] = { { .device = &s3_spea_mirage_p64_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &s3_diamond_stealth64_968_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &s3_stb_powergraph_64_video_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &ht216_32_standalone_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &tgui9400cxi_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &tgui9440_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000w32_machspeed_vga_gui_2400s_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000w32i_hercules_dynamite_pro_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000w32p_videomagic_revb_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000w32p_cardex_revc_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000w32p_generic_revd_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000w32p_cardex_revd_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000w32p_diamond_revd_vlb_device, .flags = VIDEO_FLAG_TYPE_NONE }, /* PCI */ + { .device = &voodoo_banshee_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &voodoo_3_1000_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &voodoo_3_2000_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &voodoo_3_3000_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &mach32_pci_device, .flags = VIDEO_FLAG_TYPE_8514 }, { .device = &mach64gx_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &mach64ct_device, .flags = VIDEO_FLAG_TYPE_NONE }, @@ -197,10 +201,12 @@ video_cards[] = { { .device = &gd5446_pci_device, .flags = VIDEO_FLAG_TYPE_SECONDARY }, { .device = &gd5446_stb_pci_device, .flags = VIDEO_FLAG_TYPE_SECONDARY }, { .device = &gd5480_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &et4000w32p_cardex_revc_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &et4000w32p_generic_revd_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &et4000w32p_cardex_revd_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &et4000w32p_diamond_revd_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &creative_voodoo_banshee_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &millennium_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &millennium_ii_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &mystique_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &mystique_220_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &quantum3d_raven_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &s3_elsa_winner1000_86c928_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &s3_spea_mercury_lite_86c928_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &s3_diamond_stealth64_964_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, @@ -234,26 +240,14 @@ video_cards[] = { { .device = &s3_virge_385_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &s3_virge_357_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &s3_trio3d2x_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &millennium_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &millennium_ii_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &mystique_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &mystique_220_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &tgui9440_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &tgui9660_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &tgui9680_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &voodoo_banshee_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &creative_voodoo_banshee_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &quantum3d_raven_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &voodoo_3_1000_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &voodoo_3_2000_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &voodoo_3_3000_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000w32p_cardex_revc_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000w32p_generic_revd_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000w32p_cardex_revd_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &et4000w32p_diamond_revd_pci_device, .flags = VIDEO_FLAG_TYPE_NONE }, /* AGP */ - { .device = &s3_virge_357_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &s3_diamond_stealth_4000_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &s3_trio3d2x_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, -#ifdef USE_G100 - { .device = &productiva_g100_device, .flags = VIDEO_FLAG_TYPE_SPECIAL }, -#endif /*USE_G100 */ { .device = &velocity_100_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &velocity_200_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &voodoo_3_1000_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, @@ -261,9 +255,15 @@ video_cards[] = { { .device = &voodoo_3_3000_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &voodoo_3_3500_agp_ntsc_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &voodoo_3_3500_agp_pal_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &voodoo_3_3500_si_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &compaq_voodoo_3_3500_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = &voodoo_3_3500_se_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, - { .device = &voodoo_3_3500_si_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, +#ifdef USE_G100 + { .device = &productiva_g100_device, .flags = VIDEO_FLAG_TYPE_SPECIAL }, +#endif /*USE_G100 */ + { .device = &s3_virge_357_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_diamond_stealth_4000_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, + { .device = &s3_trio3d2x_agp_device, .flags = VIDEO_FLAG_TYPE_NONE }, { .device = NULL, .flags = VIDEO_FLAG_TYPE_NONE } // clang-format on }; @@ -360,7 +360,7 @@ video_reset(int card) card, machine_has_flags(machine, MACHINE_VIDEO) ? 1 : 0); monitor_index_global = 0; - loadfont(FONT_IBM_MDA_437_PATH, 0); + video_load_font(FONT_IBM_MDA_437_PATH, FONT_FORMAT_MDA, LOAD_FONT_NO_OFFSET); for (uint8_t i = 1; i < GFXCARD_MAX; i ++) { if ((card != VID_NONE) && !machine_has_flags(machine, MACHINE_VIDEO_ONLY) && @@ -389,6 +389,10 @@ video_reset(int card) void video_post_reset(void) { + /* Reset the graphics card (or do nothing if it was already done + by the machine's init function). */ + video_reset(gfxcard[0]); + int ibm8514_has_vga = 0; if (gfxcard[0] == VID_INTERNAL) ibm8514_has_vga = (video_get_type_monitor(0) == VIDEO_FLAG_TYPE_8514); @@ -408,9 +412,6 @@ video_post_reset(void) if (da2_standalone_enabled) da2_device_add(); - /* Reset the graphics card (or do nothing if it was already done - by the machine's init function). */ - video_reset(gfxcard[0]); } void @@ -482,21 +483,3 @@ video_is_cga(void) { return (video_get_type() == VIDEO_FLAG_TYPE_CGA); } - -int -video_is_ega_vga(void) -{ - return (video_get_type() == VIDEO_FLAG_TYPE_SPECIAL); -} - -int -video_is_8514(void) -{ - return (video_get_type() == VIDEO_FLAG_TYPE_8514); -} - -int -video_is_xga(void) -{ - return (video_get_type() == VIDEO_FLAG_TYPE_XGA); -} diff --git a/src/video/vid_tandy.c b/src/video/vid_tandy.c index 0130fb7be5d..741719cd05b 100644 --- a/src/video/vid_tandy.c +++ b/src/video/vid_tandy.c @@ -1029,7 +1029,7 @@ const device_config_t sl_vid_config[] = { }; const device_t tandy_1000_video_device = { - .name = "Tandy 1000", + .name = "Tandy 1000 SX (Video)", .internal_name = "tandy1000_video", .flags = 0, .local = 0, @@ -1043,7 +1043,7 @@ const device_t tandy_1000_video_device = { }; const device_t tandy_1000hx_video_device = { - .name = "Tandy 1000 HX", + .name = "Tandy 1000 HX (Video)", .internal_name = "tandy1000_hx_video", .flags = 0, .local = 0, @@ -1057,7 +1057,7 @@ const device_t tandy_1000hx_video_device = { }; const device_t tandy_1000sl_video_device = { - .name = "Tandy 1000SL2", + .name = "Tandy 1000SL2 (Video)", .internal_name = "tandy1000_sl_video", .flags = 0, .local = 1, diff --git a/src/video/vid_tgui9440.c b/src/video/vid_tgui9440.c index 30f76abfa77..28c02363c73 100644 --- a/src/video/vid_tgui9440.c +++ b/src/video/vid_tgui9440.c @@ -161,7 +161,7 @@ typedef struct tgui_t { uint8_t ramdac_ctrl; uint8_t alt_clock; - int clock_m, clock_n, clock_k; + uint16_t vclk; uint32_t vram_size, vram_mask; @@ -567,17 +567,18 @@ tgui_out(uint16_t addr, uint8_t val, void *priv) return; case 0x3DB: - tgui->alt_clock = val & 0xe3; + tgui->alt_clock = val; + svga_recalctimings(svga); return; case 0x43c8: - tgui->clock_n = val & 0x7f; - tgui->clock_m = (tgui->clock_m & ~1) | (val >> 7); - break; + tgui->vclk = (tgui->vclk & 0xff00) | val; + svga_recalctimings(svga); + return; case 0x43c9: - tgui->clock_m = (tgui->clock_m & ~0x1e) | ((val << 1) & 0x1e); - tgui->clock_k = (val & 0x10) >> 4; - break; + tgui->vclk = (tgui->vclk & 0x00ff) | (val << 8); + svga_recalctimings(svga); + return; default: break; @@ -693,6 +694,9 @@ tgui_recalctimings(svga_t *svga) uint8_t ger22lower = (tgui->accel.ger22 & 0xff); uint8_t ger22upper = (tgui->accel.ger22 >> 8); int std_vga_clock = 1; + int m = 0; + int n = 0; + int k = 0; if (tgui->type >= TGUI_9440) { if ((svga->crtc[0x38] & 0x19) == 0x09) @@ -764,13 +768,23 @@ tgui_recalctimings(svga_t *svga) svga->lowres = !(svga->crtc[0x2a] & 0x40); if (tgui->type >= TGUI_9440) { - if (svga->miscout & 8) - svga->clock = (cpuclock * (double) (1ULL << 32)) / (((tgui->clock_n + 8) * 14318180.0) / ((tgui->clock_m + 2) * (1 << tgui->clock_k))); + // Bits 0-6: M + // Bits 7-11: N + // Bit 12: K + // Later formula extends each variable by one extra bit (Providia 9685 and later) + if (((svga->miscout & 0x0c) >> 2) == 0x02) { + m = tgui->vclk & 0x007f; + n = (tgui->vclk & 0x0f80) >> 7; + k = (tgui->vclk & 0x1000) >> 12; + svga->clock = (cpuclock * (double) (1ULL << 32)) / (((m + 8) * 14318180.0) / ((n + 2) * (1 << k))); + } - if (svga->gdcreg[0xf] & 0x08) + if ((svga->gdcreg[0xf] & 0x08) || (tgui->alt_clock & 0x20)) svga->clock *= 2.0; else if (svga->gdcreg[0xf] & 0x40) svga->clock *= 3.0; + + pclog("GDCREGF=%02x, miscout=%02x.\n", svga->gdcreg[0xf] & 0x48, svga->miscout & 0x0c); } else { //pclog("TGUI9400CXi: Clock double=%d.\n", (((svga->miscout >> 2) & 3) | ((tgui->newctrl2 << 2) & 4) | ((tgui->newctrl2 >> 3) & 8))); switch (((svga->miscout >> 2) & 3) | ((tgui->newctrl2 << 2) & 4) | ((tgui->newctrl2 >> 3) & 8)) { diff --git a/src/video/vid_voodoo.c b/src/video/vid_voodoo.c index b070e7aba63..72a57e66c7b 100644 --- a/src/video/vid_voodoo.c +++ b/src/video/vid_voodoo.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -73,6 +74,66 @@ voodoo_log(const char *fmt, ...) # define voodoo_log(fmt, ...) #endif +static int +voodoo_env_is_disabled(const char *value) +{ + /* Accept common "off" values for env overrides. */ + return !strcmp(value, "0") || !strcmp(value, "off") || !strcmp(value, "false") || !strcmp(value, "disabled"); +} + +static void +voodoo_init_relax_settings(voodoo_t *voodoo) +{ + const char *relax_env = getenv("VOODOO_LFB_RELAX"); + const char *wait_env = getenv("VOODOO_WAIT_STATS"); + int relax_enabled = 1; + + /* Default to front-sync relax mode; wait stats are opt-in. */ + if (!relax_env || !*relax_env) { + relax_env = "4"; + } else if (voodoo_env_is_disabled(relax_env)) { + relax_enabled = 0; + } + + voodoo->wait_stats_explicit = (wait_env && *wait_env); + voodoo->wait_stats_enabled = voodoo->wait_stats_explicit && !voodoo_env_is_disabled(wait_env); + + voodoo->lfb_relax_enabled = relax_enabled; + voodoo->lfb_relax_full = relax_enabled && (strcmp(relax_env, "full") == 0); + voodoo->lfb_relax_ignore_cmdfifo = relax_enabled && (!strcmp(relax_env, "nocmdfifo") || !strcmp(relax_env, "2") || !strcmp(relax_env, "3") || !strcmp(relax_env, "4") || !strcmp(relax_env, "frontsync")); + voodoo->lfb_relax_ignore_draw = relax_enabled && (!strcmp(relax_env, "nodraw") || !strcmp(relax_env, "2") || !strcmp(relax_env, "3") || !strcmp(relax_env, "4") || !strcmp(relax_env, "frontsync")); + voodoo->lfb_relax_ignore_fb_writes = relax_enabled && (!strcmp(relax_env, "nowrites") || !strcmp(relax_env, "3") || !strcmp(relax_env, "4") || !strcmp(relax_env, "frontsync")); + voodoo->lfb_relax_front_sync = relax_enabled && (!strcmp(relax_env, "4") || !strcmp(relax_env, "frontsync")); +} + +static void +voodoo_update_queued_buffers(voodoo_t *voodoo) +{ + switch (voodoo->queued_lfbMode & LFB_WRITE_MASK) { + case LFB_WRITE_FRONT: + voodoo->queued_fb_write_buffer = voodoo->queued_disp_buffer; + break; + case LFB_WRITE_BACK: + voodoo->queued_fb_write_buffer = voodoo->queued_draw_buffer; + break; + default: + voodoo->queued_fb_write_buffer = voodoo->queued_disp_buffer; + break; + } + + switch (voodoo->queued_fbzMode & FBZ_DRAW_MASK) { + case FBZ_DRAW_FRONT: + voodoo->queued_fb_draw_buffer = voodoo->queued_disp_buffer; + break; + case FBZ_DRAW_BACK: + voodoo->queued_fb_draw_buffer = voodoo->queued_draw_buffer; + break; + default: + voodoo->queued_fb_draw_buffer = voodoo->queued_draw_buffer; + break; + } +} + void voodoo_recalc(voodoo_t *voodoo) { @@ -167,11 +228,69 @@ voodoo_readw(uint32_t addr, void *priv) voodoo = set->voodoos[0]; } - voodoo->flush = 1; - while (!FIFO_EMPTY) - voodoo_wake_fifo_thread_now(voodoo); - voodoo_wait_for_render_thread_idle(voodoo); - voodoo->flush = 0; + /* Reads from aux/draw/write regions must see completed rendering. */ + int need_sync = (voodoo->fb_read_offset == voodoo->params.aux_offset) || + (voodoo->fb_read_offset == voodoo->params.draw_offset) || + (voodoo->fb_read_offset == voodoo->fb_write_offset); + int do_sync = 0; + int read_buf = -1; + + if (voodoo->fb_read_offset == voodoo->params.front_offset) + read_buf = VOODOO_BUF_FRONT; + else if (voodoo->fb_read_offset == voodoo->back_offset) + read_buf = VOODOO_BUF_BACK; + else if (voodoo->fb_read_offset == voodoo->params.aux_offset) + read_buf = VOODOO_BUF_AUX; + + if (!need_sync && voodoo->lfb_relax_front_sync && read_buf >= 0 && read_buf != VOODOO_BUF_BACK) + need_sync = 1; + + if (need_sync) { + if (!voodoo->lfb_relax_enabled) + do_sync = 1; + else if (voodoo->lfb_relax_full) + do_sync = 0; + else { + /* In relax mode, only back-buffer reads can skip the full FIFO flush. */ + int pending_buf = 0; + int pending_unknown = 0; + + if (read_buf >= 0 && read_buf < VOODOO_BUF_COUNT) { + if (!voodoo->lfb_relax_ignore_fb_writes) + pending_buf += voodoo->pending_fb_writes_buf[read_buf]; + if (!voodoo->lfb_relax_ignore_draw) + pending_buf += voodoo->pending_draw_cmds_buf[read_buf]; + } + + if (!voodoo->lfb_relax_ignore_fb_writes) + pending_unknown += voodoo->pending_fb_writes_buf[VOODOO_BUF_UNKNOWN]; + if (!voodoo->lfb_relax_ignore_draw) + pending_unknown += voodoo->pending_draw_cmds_buf[VOODOO_BUF_UNKNOWN]; + if (!voodoo->lfb_relax_ignore_cmdfifo) { + if ((voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr) || voodoo->cmdfifo_in_sub) + pending_unknown++; + if ((voodoo->cmdfifo_depth_rd_2 != voodoo->cmdfifo_depth_wr_2) || voodoo->cmdfifo_in_sub_2) + pending_unknown++; + } + + if (read_buf != VOODOO_BUF_BACK) + do_sync = 1; + else + do_sync = (pending_buf || pending_unknown); + } + + if (do_sync) { + voodoo->flush = 1; + while (!FIFO_EMPTY) { + voodoo_wake_fifo_thread_now(voodoo); + thread_wait_event(voodoo->fifo_empty_event, -1); + } + voodoo_wait_for_render_thread_idle(voodoo); + voodoo->flush = 0; + } else if (voodoo->lfb_relax_enabled && !voodoo->lfb_relax_full) { + voodoo_wait_for_render_thread_idle(voodoo); + } + } return voodoo_fb_readw(addr, voodoo); } @@ -191,8 +310,17 @@ voodoo_readl(uint32_t addr, void *priv) cycles -= voodoo->read_time; if (addr & 0x800000) { /*Texture*/ + if (voodoo->wait_stats_enabled) + voodoo->readl_tex_count++; } else if (addr & 0x400000) /*Framebuffer*/ { + uint64_t fifo_wait_start = 0; + uint64_t fifo_wait_spins = 0; + int fifo_wait_active = 0; + int need_sync = 0; + int do_sync = 0; + int read_buf = -1; + if (SLI_ENABLED) { const voodoo_set_t *set = voodoo->set; int y = (addr >> 11) & 0x3ff; @@ -203,23 +331,116 @@ voodoo_readl(uint32_t addr, void *priv) voodoo = set->voodoos[0]; } - voodoo->flush = 1; - while (!FIFO_EMPTY) { - voodoo_wake_fifo_thread_now(voodoo); - thread_wait_event(voodoo->fifo_not_full_event, 1); + if (voodoo->wait_stats_enabled) + voodoo->readl_fb_count++; + + if (voodoo->fb_read_offset == voodoo->params.front_offset) + read_buf = VOODOO_BUF_FRONT; + else if (voodoo->fb_read_offset == voodoo->back_offset) + read_buf = VOODOO_BUF_BACK; + else if (voodoo->fb_read_offset == voodoo->params.aux_offset) + read_buf = VOODOO_BUF_AUX; + + /* Reads from aux/draw/write regions must see completed rendering. */ + need_sync = (voodoo->fb_read_offset == voodoo->params.aux_offset) || + (voodoo->fb_read_offset == voodoo->params.draw_offset) || + (voodoo->fb_read_offset == voodoo->fb_write_offset); + if (!need_sync && voodoo->lfb_relax_front_sync && read_buf >= 0 && read_buf != VOODOO_BUF_BACK) + need_sync = 1; + if (need_sync) { + if (!voodoo->lfb_relax_enabled) + do_sync = 1; + else if (voodoo->lfb_relax_full) + do_sync = 0; + else { + /* In relax mode, only back-buffer reads can skip the full FIFO flush. */ + int pending_buf = 0; + int pending_unknown = 0; + + if (read_buf >= 0 && read_buf < VOODOO_BUF_COUNT) { + if (!voodoo->lfb_relax_ignore_fb_writes) + pending_buf += voodoo->pending_fb_writes_buf[read_buf]; + if (!voodoo->lfb_relax_ignore_draw) + pending_buf += voodoo->pending_draw_cmds_buf[read_buf]; + } + + if (!voodoo->lfb_relax_ignore_fb_writes) + pending_unknown += voodoo->pending_fb_writes_buf[VOODOO_BUF_UNKNOWN]; + if (!voodoo->lfb_relax_ignore_draw) + pending_unknown += voodoo->pending_draw_cmds_buf[VOODOO_BUF_UNKNOWN]; + if (!voodoo->lfb_relax_ignore_cmdfifo) { + if ((voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr) || voodoo->cmdfifo_in_sub) + pending_unknown++; + if ((voodoo->cmdfifo_depth_rd_2 != voodoo->cmdfifo_depth_wr_2) || voodoo->cmdfifo_in_sub_2) + pending_unknown++; + } + + if (read_buf != VOODOO_BUF_BACK) + do_sync = 1; + else + do_sync = (pending_buf || pending_unknown); + } + } + + if (voodoo->wait_stats_enabled) { + if (do_sync) + voodoo->readl_fb_sync_count++; + else + voodoo->readl_fb_nosync_count++; + if (read_buf >= 0) { + if (do_sync) + voodoo->readl_fb_sync_buf[read_buf]++; + else + voodoo->readl_fb_nosync_buf[read_buf]++; + } + if (need_sync && voodoo->lfb_relax_enabled && !do_sync) { + voodoo->readl_fb_relaxed_count++; + if (read_buf >= 0) + voodoo->readl_fb_relaxed_buf[read_buf]++; + } + } + + if (do_sync) { + voodoo->flush = 1; + while (!FIFO_EMPTY) { + if (voodoo->wait_stats_enabled) { + if (!fifo_wait_active) { + fifo_wait_active = 1; + fifo_wait_start = plat_timer_read(); + voodoo->fifo_empty_waits++; + } + fifo_wait_spins++; + } + voodoo_wake_fifo_thread_now(voodoo); + thread_wait_event(voodoo->fifo_empty_event, -1); + } + if (fifo_wait_active) { + voodoo->fifo_empty_wait_ticks += plat_timer_read() - fifo_wait_start; + voodoo->fifo_empty_spin_checks += fifo_wait_spins; + } + voodoo_wait_for_render_thread_idle(voodoo); + voodoo->flush = 0; + } else if (need_sync && voodoo->lfb_relax_enabled && !voodoo->lfb_relax_full) { + voodoo_wait_for_render_thread_idle(voodoo); } - voodoo_wait_for_render_thread_idle(voodoo); - voodoo->flush = 0; temp = voodoo_fb_readl(addr, voodoo); - } else + } else { + if (voodoo->wait_stats_enabled) + voodoo->readl_reg_count++; + switch (addr & 0x3fc) { case SST_status: { int fifo_entries = FIFO_ENTRIES; int swap_count = voodoo->swap_count; int written = voodoo->cmd_written + voodoo->cmd_written_fifo + voodoo->cmd_written_fifo_2; - int busy = (written - voodoo->cmd_read) || (voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr); + int busy = (written - voodoo->cmd_read) || + (voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr) || + voodoo->voodoo_busy || + voodoo->render_voodoo_busy[0] || + (voodoo->render_threads >= 2 && voodoo->render_voodoo_busy[1]) || + (voodoo->render_threads == 4 && (voodoo->render_voodoo_busy[2] || voodoo->render_voodoo_busy[3])); if (SLI_ENABLED && voodoo->type != VOODOO_2) { voodoo_t *voodoo_other = (voodoo == voodoo->set->voodoos[0]) ? voodoo->set->voodoos[1] : voodoo->set->voodoos[0]; @@ -229,7 +450,12 @@ voodoo_readl(uint32_t addr, void *priv) swap_count = voodoo_other->swap_count; if ((voodoo_other->fifo_write_idx - voodoo_other->fifo_read_idx) > fifo_entries) fifo_entries = voodoo_other->fifo_write_idx - voodoo_other->fifo_read_idx; - if ((other_written - voodoo_other->cmd_read) || (voodoo_other->cmdfifo_depth_rd != voodoo_other->cmdfifo_depth_wr)) + if ((other_written - voodoo_other->cmd_read) || + (voodoo_other->cmdfifo_depth_rd != voodoo_other->cmdfifo_depth_wr) || + voodoo_other->voodoo_busy || + voodoo_other->render_voodoo_busy[0] || + (voodoo_other->render_threads >= 2 && voodoo_other->render_voodoo_busy[1]) || + (voodoo_other->render_threads == 4 && (voodoo_other->render_voodoo_busy[2] || voodoo_other->render_voodoo_busy[3]))) busy = 1; if (!voodoo_other->voodoo_busy) voodoo_wake_fifo_thread(voodoo_other); @@ -338,11 +564,11 @@ voodoo_readl(uint32_t addr, void *priv) break; case SST_hvRetrace: { - uint32_t line_time = (uint32_t) (voodoo->line_time >> 32); - uint32_t diff = (timer_get_ts_int(&voodoo->timer) > (tsc & 0xffffffff)) ? (timer_get_ts_int(&voodoo->timer) - (tsc & 0xffffffff)) : 0; - uint32_t pre_div = diff * voodoo->h_total; - uint32_t post_div = pre_div / line_time; - uint32_t h_pos = (voodoo->h_total - 1) - post_div; + uint64_t line_time = (uint64_t) (voodoo->line_time >> 32); + uint64_t diff = (timer_get_ts_int(&voodoo->timer) > tsc) ? (timer_get_ts_int(&voodoo->timer) - tsc) : 0; + uint64_t pre_div = diff * voodoo->h_total; + uint64_t post_div = pre_div / line_time; + uint64_t h_pos = (voodoo->h_total - 1) - post_div; if (h_pos >= voodoo->h_total) h_pos = 0; @@ -384,6 +610,7 @@ voodoo_readl(uint32_t addr, void *priv) voodoo_log("voodoo_readl : bad addr %08X\n", addr); temp = 0xffffffff; } + } return temp; } @@ -432,7 +659,7 @@ voodoo_writel(uint32_t addr, uint32_t val, void *priv) /* Voodoo1: use higher CMDFIFO threshold to reduce wake frequency */ if (voodoo->type == VOODOO_1) { - if ((voodoo->cmdfifo_depth_wr - voodoo->cmdfifo_depth_rd) > 300) + if ((voodoo->cmdfifo_depth_wr - voodoo->cmdfifo_depth_rd) < 20) voodoo_wake_fifo_thread(voodoo); } /* Other cards (Voodoo2, Banshee, Voodoo3, ...) keep the original behavior */ @@ -516,6 +743,7 @@ voodoo_writel(uint32_t addr, uint32_t val, void *priv) break; case SST_fbiInit0: if (voodoo->initEnable & 0x01) { + int old_vga_pass = voodoo->fbiInit0 & FBIINIT0_VGA_PASS; voodoo->fbiInit0 = val; thread_wait_mutex(voodoo->force_blit_mutex); voodoo->can_blit = (voodoo->fbiInit0 & FBIINIT0_VGA_PASS) ? 1 : 0; @@ -523,6 +751,10 @@ voodoo_writel(uint32_t addr, uint32_t val, void *priv) voodoo->force_blit_count = 0; thread_release_mutex(voodoo->force_blit_mutex); + /* When VGA pass-through becomes active, mark all lines dirty to force full refresh */ + if (!old_vga_pass && (val & FBIINIT0_VGA_PASS)) + memset(voodoo->dirty_line, 1, sizeof(voodoo->dirty_line)); + if (voodoo->set->nr_cards == 2) svga_set_override(voodoo->svga, (voodoo->set->voodoos[0]->fbiInit0 | voodoo->set->voodoos[1]->fbiInit0) & 1); else @@ -532,6 +764,11 @@ voodoo_writel(uint32_t addr, uint32_t val, void *priv) happen here on a real Voodoo*/ voodoo->disp_buffer = 0; voodoo->draw_buffer = 1; + voodoo->queued_disp_buffer = voodoo->disp_buffer; + voodoo->queued_draw_buffer = voodoo->draw_buffer; + voodoo->queued_lfbMode = voodoo->lfbMode; + voodoo->queued_fbzMode = voodoo->params.fbzMode; + voodoo_update_queued_buffers(voodoo); voodoo_recalc(voodoo); voodoo->front_offset = voodoo->params.front_offset; } @@ -920,6 +1157,7 @@ voodoo_card_init(void) voodoo_t *voodoo = malloc(sizeof(voodoo_t)); memset(voodoo, 0, sizeof(voodoo_t)); + voodoo_init_relax_settings(voodoo); voodoo->bilinear_enabled = device_get_config_int("bilinear"); voodoo->dithersub_enabled = device_get_config_int("dithersub"); voodoo->scrfilter = device_get_config_int("dacfilter"); @@ -987,6 +1225,9 @@ voodoo_card_init(void) voodoo->wake_render_thread[3] = thread_create_event(); voodoo->wake_main_thread = thread_create_event(); voodoo->fifo_not_full_event = thread_create_event(); + voodoo->fifo_empty_event = thread_create_event(); + thread_set_event(voodoo->fifo_empty_event); + ATOMIC_STORE(voodoo->fifo_empty_signaled, 1); voodoo->render_not_full_event[0] = thread_create_event(); voodoo->render_not_full_event[1] = thread_create_event(); voodoo->render_not_full_event[2] = thread_create_event(); @@ -1060,6 +1301,11 @@ voodoo_card_init(void) voodoo->disp_buffer = 0; voodoo->draw_buffer = 1; + voodoo->queued_disp_buffer = voodoo->disp_buffer; + voodoo->queued_draw_buffer = voodoo->draw_buffer; + voodoo->queued_lfbMode = voodoo->lfbMode; + voodoo->queued_fbzMode = voodoo->params.fbzMode; + voodoo_update_queued_buffers(voodoo); voodoo->force_blit_count = 0; voodoo->can_blit = 0; @@ -1075,6 +1321,7 @@ voodoo_2d3d_card_init(int type) voodoo_t *voodoo = malloc(sizeof(voodoo_t)); memset(voodoo, 0, sizeof(voodoo_t)); + voodoo_init_relax_settings(voodoo); voodoo->bilinear_enabled = device_get_config_int("bilinear"); voodoo->dithersub_enabled = device_get_config_int("dithersub"); voodoo->scrfilter = device_get_config_int("dacfilter"); @@ -1111,6 +1358,9 @@ voodoo_2d3d_card_init(int type) voodoo->wake_render_thread[3] = thread_create_event(); voodoo->wake_main_thread = thread_create_event(); voodoo->fifo_not_full_event = thread_create_event(); + voodoo->fifo_empty_event = thread_create_event(); + thread_set_event(voodoo->fifo_empty_event); + ATOMIC_STORE(voodoo->fifo_empty_signaled, 1); voodoo->render_not_full_event[0] = thread_create_event(); voodoo->render_not_full_event[1] = thread_create_event(); voodoo->render_not_full_event[2] = thread_create_event(); @@ -1184,6 +1434,11 @@ voodoo_2d3d_card_init(int type) voodoo->disp_buffer = 0; voodoo->draw_buffer = 1; + voodoo->queued_disp_buffer = voodoo->disp_buffer; + voodoo->queued_draw_buffer = voodoo->draw_buffer; + voodoo->queued_lfbMode = voodoo->lfbMode; + voodoo->queued_fbzMode = voodoo->params.fbzMode; + voodoo_update_queued_buffers(voodoo); voodoo->force_blit_count = 0; voodoo->can_blit = 0; @@ -1272,6 +1527,7 @@ voodoo_card_close(voodoo_t *voodoo) thread_wait(voodoo->render_thread[3]); } thread_destroy_event(voodoo->fifo_not_full_event); + thread_destroy_event(voodoo->fifo_empty_event); thread_destroy_event(voodoo->wake_main_thread); thread_destroy_event(voodoo->wake_fifo_thread); thread_destroy_event(voodoo->wake_render_thread[0]); @@ -1279,6 +1535,48 @@ voodoo_card_close(voodoo_t *voodoo) thread_destroy_event(voodoo->render_not_full_event[0]); thread_destroy_event(voodoo->render_not_full_event[1]); + if (voodoo->wait_stats_enabled && voodoo->wait_stats_explicit) { + pclog("Voodoo wait stats (type=%d): fifo_full waits=%" PRIu64 " ticks=%" PRIu64 " spins=%" PRIu64 + ", fifo_empty waits=%" PRIu64 " ticks=%" PRIu64 " spins=%" PRIu64 + ", render_wait waits=%" PRIu64 " ticks=%" PRIu64 " spins=%" PRIu64 + ", readl fb=%" PRIu64 " sync=%" PRIu64 " nosync=%" PRIu64 " relaxed=%" PRIu64 " relax=%d full=%d nocmdfifo=%d nodraw=%d nowrites=%d frontsync=%d" + " sync_buf f=%" PRIu64 " b=%" PRIu64 " a=%" PRIu64 + " nosync_buf f=%" PRIu64 " b=%" PRIu64 " a=%" PRIu64 + " relaxed_buf f=%" PRIu64 " b=%" PRIu64 " a=%" PRIu64 + " reg=%" PRIu64 " tex=%" PRIu64 "\n", + voodoo->type, + voodoo->fifo_full_waits, + voodoo->fifo_full_wait_ticks, + voodoo->fifo_full_spin_checks, + voodoo->fifo_empty_waits, + voodoo->fifo_empty_wait_ticks, + voodoo->fifo_empty_spin_checks, + voodoo->render_waits, + voodoo->render_wait_ticks, + voodoo->render_wait_spin_checks, + voodoo->readl_fb_count, + voodoo->readl_fb_sync_count, + voodoo->readl_fb_nosync_count, + voodoo->readl_fb_relaxed_count, + voodoo->lfb_relax_enabled, + voodoo->lfb_relax_full, + voodoo->lfb_relax_ignore_cmdfifo, + voodoo->lfb_relax_ignore_draw, + voodoo->lfb_relax_ignore_fb_writes, + voodoo->lfb_relax_front_sync, + voodoo->readl_fb_sync_buf[0], + voodoo->readl_fb_sync_buf[1], + voodoo->readl_fb_sync_buf[2], + voodoo->readl_fb_nosync_buf[0], + voodoo->readl_fb_nosync_buf[1], + voodoo->readl_fb_nosync_buf[2], + voodoo->readl_fb_relaxed_buf[0], + voodoo->readl_fb_relaxed_buf[1], + voodoo->readl_fb_relaxed_buf[2], + voodoo->readl_reg_count, + voodoo->readl_tex_count); + } + for (uint8_t c = 0; c < TEX_CACHE_MAX; c++) { if (voodoo->dual_tmus) free(voodoo->texture_cache[1][c].data); diff --git a/src/video/vid_voodoo_banshee.c b/src/video/vid_voodoo_banshee.c index abccff8605d..f914c7e866e 100644 --- a/src/video/vid_voodoo_banshee.c +++ b/src/video/vid_voodoo_banshee.c @@ -129,6 +129,7 @@ typedef struct banshee_t { uint32_t agpHostAddressLow; uint32_t agpGraphicsAddress; uint32_t agpGraphicsStride; + uint32_t agpMoveCMD; int overlay_pix_fmt; @@ -1372,6 +1373,10 @@ banshee_cmd_read(banshee_t *banshee, uint32_t addr) ret = banshee->agpReqSize; break; + case Agp_agpMoveCMD: + ret = banshee->agpMoveCMD; + break; + case cmdBaseAddr0: ret = voodoo->cmdfifo_base >> 12; #if 0 @@ -1694,6 +1699,7 @@ banshee_cmd_write(void *priv, uint32_t addr, uint32_t val) #if 0 banshee_log("AGP: %d bytes W%d from %08x S%d to %d:%08x S%d\n", src_end - src_addr, src_width, src_addr, src_stride, (val >> 3) & 3, dest_addr, dest_stride); #endif + banshee->agpMoveCMD = val; switch ((val >> 3) & 3) { case 0: /*Linear framebuffer (Banshee)*/ case 1: /*Planar YUV*/ diff --git a/src/video/vid_voodoo_banshee_blitter.c b/src/video/vid_voodoo_banshee_blitter.c index ac8cb172d31..af609d78571 100644 --- a/src/video/vid_voodoo_banshee_blitter.c +++ b/src/video/vid_voodoo_banshee_blitter.c @@ -1438,9 +1438,30 @@ banshee_polyfill_continue(voodoo_t *voodoo, uint32_t data) } } +static inline void +banshee_do_2d_launch(voodoo_t *voodoo) +{ + voodoo->launch_pending = 0; + voodoo->banshee_blt.rops[0] = voodoo->banshee_blt.command >> 24; + voodoo->banshee_blt.patoff_x = (voodoo->banshee_blt.command & COMMAND_PATOFF_X_MASK) >> COMMAND_PATOFF_X_SHIFT; + voodoo->banshee_blt.patoff_y = (voodoo->banshee_blt.command & COMMAND_PATOFF_Y_MASK) >> COMMAND_PATOFF_Y_SHIFT; + voodoo->banshee_blt.cur_x = 0; + voodoo->banshee_blt.cur_y = 0; + voodoo->banshee_blt.dstX = ((int32_t) (voodoo->banshee_blt.dstXY << 19)) >> 19; + voodoo->banshee_blt.dstY = ((int32_t) (voodoo->banshee_blt.dstXY << 3)) >> 19; + voodoo->banshee_blt.srcX = ((int32_t) (voodoo->banshee_blt.srcXY << 19)) >> 19; + voodoo->banshee_blt.srcY = ((int32_t) (voodoo->banshee_blt.srcXY << 3)) >> 19; + voodoo->banshee_blt.old_srcX = voodoo->banshee_blt.srcX; + voodoo->banshee_blt.host_data_remainder = 0; + voodoo->banshee_blt.host_data_count = 0; +} + static void banshee_do_2d_blit(voodoo_t *voodoo, int count, uint32_t data) { + if (voodoo->launch_pending) { + banshee_do_2d_launch(voodoo); + } switch (voodoo->banshee_blt.command & COMMAND_CMD_MASK) { case COMMAND_CMD_NOP: break; @@ -1691,21 +1712,7 @@ voodoo_2d_reg_writel(voodoo_t *voodoo, uint32_t addr, uint32_t val) case 0x70: voodoo_wait_for_render_thread_idle(voodoo); voodoo->banshee_blt.command = val; - voodoo->banshee_blt.rops[0] = val >> 24; -#if 0 - bansheeblt_log("command=%x %08x\n", voodoo->banshee_blt.command & COMMAND_CMD_MASK, val); -#endif - voodoo->banshee_blt.patoff_x = (val & COMMAND_PATOFF_X_MASK) >> COMMAND_PATOFF_X_SHIFT; - voodoo->banshee_blt.patoff_y = (val & COMMAND_PATOFF_Y_MASK) >> COMMAND_PATOFF_Y_SHIFT; - voodoo->banshee_blt.cur_x = 0; - voodoo->banshee_blt.cur_y = 0; - voodoo->banshee_blt.dstX = ((int32_t) (voodoo->banshee_blt.dstXY << 19)) >> 19; - voodoo->banshee_blt.dstY = ((int32_t) (voodoo->banshee_blt.dstXY << 3)) >> 19; - voodoo->banshee_blt.srcX = ((int32_t) (voodoo->banshee_blt.srcXY << 19)) >> 19; - voodoo->banshee_blt.srcY = ((int32_t) (voodoo->banshee_blt.srcXY << 3)) >> 19; - voodoo->banshee_blt.old_srcX = voodoo->banshee_blt.srcX; - voodoo->banshee_blt.host_data_remainder = 0; - voodoo->banshee_blt.host_data_count = 0; + voodoo->launch_pending = 1; switch (voodoo->banshee_blt.command & COMMAND_CMD_MASK) { #if 0 @@ -1725,6 +1732,7 @@ voodoo_2d_reg_writel(voodoo_t *voodoo, uint32_t addr, uint32_t val) #endif case COMMAND_CMD_POLYFILL: + banshee_do_2d_launch(voodoo); if (val & COMMAND_INITIATE) { voodoo->banshee_blt.dstXY = voodoo->banshee_blt.srcXY; voodoo->banshee_blt.dstX = voodoo->banshee_blt.srcX; @@ -1733,6 +1741,10 @@ voodoo_2d_reg_writel(voodoo_t *voodoo, uint32_t addr, uint32_t val) banshee_polyfill_start(voodoo); break; + case COMMAND_CMD_HOST_TO_SCREEN_BLT: + case COMMAND_CMD_HOST_TO_SCREEN_STRETCH_BLT: + break; + default: if (val & COMMAND_INITIATE) { banshee_do_2d_blit(voodoo, -1, 0); @@ -1779,6 +1791,9 @@ voodoo_2d_reg_writel(voodoo_t *voodoo, uint32_t addr, uint32_t val) #if 0 bansheeblt_log("launch %08x %08x %08x %08x\n", voodoo->banshee_blt.command, voodoo->banshee_blt.commandExtra, voodoo->banshee_blt.srcColorkeyMin, voodoo->banshee_blt.srcColorkeyMax); #endif + if (voodoo->launch_pending) { + banshee_do_2d_launch(voodoo); + } switch (voodoo->banshee_blt.command & COMMAND_CMD_MASK) { case COMMAND_CMD_SCREEN_TO_SCREEN_BLT: voodoo->banshee_blt.srcXY = val; diff --git a/src/video/vid_voodoo_blitter.c b/src/video/vid_voodoo_blitter.c index 0d2c9e103b2..87127a949b4 100644 --- a/src/video/vid_voodoo_blitter.c +++ b/src/video/vid_voodoo_blitter.c @@ -218,14 +218,7 @@ voodoo_v2_blit_start(voodoo_t *voodoo) break; case BLIT_COMMAND_CPU_TO_SCREEN: - voodoo->blt.dst_x = voodoo->bltDstX; - voodoo->blt.dst_y = voodoo->bltDstY; - voodoo->blt.cur_x = 0; - voodoo->blt.size_x = size_x; - voodoo->blt.size_y = size_y; - voodoo->blt.x_dir = x_dir; - voodoo->blt.y_dir = y_dir; - voodoo->blt.dst_stride = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstXYStride & 0x3f) * 32 * 2) : (voodoo->bltDstXYStride & 0xff8); + voodoo->launch_pending = 1; break; case BLIT_COMMAND_RECT_FILL: @@ -234,13 +227,13 @@ voodoo_v2_blit_start(voodoo_t *voodoo) int dst_x = voodoo->bltDstX; if (SLI_ENABLED) { - if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (voodoo->blt.dst_y & 1)) || ((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(voodoo->blt.dst_y & 1))) + if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (dst_y & 1)) || ((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(dst_y & 1))) goto skip_line_fill; dst = (uint16_t *) &voodoo->fb_mem[dst_base_addr + (dst_y >> 1) * dst_stride]; } else dst = (uint16_t *) &voodoo->fb_mem[dst_base_addr + dst_y * dst_stride]; - for (int x = 0; x <= size_x; x++) { + for (int x = 0; x < size_x; x++) { if (voodoo->bltCommand & BLIT_CLIPPING_ENABLED) { if (dst_x < voodoo->bltClipLeft || dst_x >= voodoo->bltClipRight || dst_y < voodoo->bltClipLowY || dst_y >= voodoo->bltClipHighY) goto skip_pixel_fill; @@ -303,6 +296,18 @@ voodoo_v2_blit_data(voodoo_t *voodoo, uint32_t data) if ((voodoo->bltCommand & BLIT_COMMAND_MASK) != BLIT_COMMAND_CPU_TO_SCREEN) return; + if (voodoo->launch_pending) { + voodoo->blt.dst_x = voodoo->bltDstX; + voodoo->blt.dst_y = voodoo->bltDstY; + voodoo->blt.cur_x = 0; + voodoo->blt.size_x = voodoo->bltSizeX; + voodoo->blt.size_y = voodoo->bltSizeY; + voodoo->blt.x_dir = (voodoo->bltSizeX > 0) ? 1 : -1; + voodoo->blt.y_dir = (voodoo->bltSizeY > 0) ? 1 : -1; + voodoo->blt.dst_stride = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstXYStride & 0x3f) * 32 * 2) : (voodoo->bltDstXYStride & 0xff8); + voodoo->launch_pending = 0; + } + if (SLI_ENABLED) { addr = base_addr + (voodoo->blt.dst_y >> 1) * voodoo->blt.dst_stride; dst = (uint16_t *) &voodoo->fb_mem[addr]; @@ -501,6 +506,9 @@ voodoo_fastfill(voodoo_t *voodoo, voodoo_params_t *params) for (int x = params->clipLeft; x < params->clipRight; x++) cbuf[x] = col; } + /* Mark line dirty for single buffer mode */ + if (params->draw_offset == params->front_offset && y < 2048) + voodoo->dirty_line[y] = 1; } } } diff --git a/src/video/vid_voodoo_display.c b/src/video/vid_voodoo_display.c index 3595d8b89e1..b126fc16590 100644 --- a/src/video/vid_voodoo_display.c +++ b/src/video/vid_voodoo_display.c @@ -645,6 +645,8 @@ voodoo_callback(void *priv) if (voodoo->dirty_line_high > voodoo->dirty_line_low || force_blit) svga_doblit(voodoo->h_disp, voodoo->v_disp - 1, voodoo->svga); + else if (voodoo->svga->override) + voodoo->svga->monitor->mon_renderedframes++; if (voodoo->clutData_dirty) { voodoo->clutData_dirty = 0; voodoo_calc_clutData(voodoo); diff --git a/src/video/vid_voodoo_fb.c b/src/video/vid_voodoo_fb.c index cb5a614d456..a97ca62a7e9 100644 --- a/src/video/vid_voodoo_fb.c +++ b/src/video/vid_voodoo_fb.c @@ -254,6 +254,19 @@ voodoo_fb_writew(uint32_t addr, uint16_t val, void *priv) int colbfog_g = 0; int colbfog_b = 0; + if (params->fbzMode & FBZ_STIPPLE) { + if (params->fbzMode & FBZ_STIPPLE_PATT) { + int index = ((y & 3) << 3) | (~x & 7); + if (!(params->stipple & (1 << index))) + goto skip_pixel; + } else { + voodoo->params.stipple = (voodoo->params.stipple << 1) | (voodoo->params.stipple >> 31); + if (!(voodoo->params.stipple & 0x80000000)) { + goto skip_pixel; + } + } + } + if (params->fbzMode & FBZ_DEPTH_ENABLE) { uint16_t old_depth = *(uint16_t *) (&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]); @@ -373,7 +386,6 @@ voodoo_fb_writel(uint32_t addr, uint32_t val, void *priv) colour_data[0].b = val & 0xff; colour_data[0].g = (val >> 8) & 0xff; colour_data[0].r = (val >> 16) & 0xff; - alpha_data[0] = 0xff; write_mask = LFB_WRITE_COLOUR; addr >>= 1; break; @@ -383,12 +395,14 @@ voodoo_fb_writel(uint32_t addr, uint32_t val, void *priv) depth_data[0] = val >> 16; write_mask = LFB_WRITE_BOTH; count = 1; + addr >>= 1; break; case LFB_FORMAT_DEPTH_RGB555: colour_data[0] = argb1555[val & 0xffff]; depth_data[0] = val >> 16; write_mask = LFB_WRITE_BOTH; count = 1; + addr >>= 1; break; case LFB_FORMAT_DEPTH_ARGB1555: colour_data[0] = argb1555[val & 0xffff]; @@ -396,6 +410,7 @@ voodoo_fb_writel(uint32_t addr, uint32_t val, void *priv) depth_data[0] = val >> 16; write_mask = LFB_WRITE_BOTH; count = 1; + addr >>= 1; break; case LFB_FORMAT_DEPTH: @@ -447,6 +462,19 @@ voodoo_fb_writel(uint32_t addr, uint32_t val, void *priv) int colbfog_g = 0; int colbfog_b = 0; + if (params->fbzMode & FBZ_STIPPLE) { + if (params->fbzMode & FBZ_STIPPLE_PATT) { + int index = ((y & 3) << 3) | (~(x + c) & 7); + if (!(params->stipple & (1 << index))) + goto skip_pixel; + } else { + voodoo->params.stipple = (voodoo->params.stipple << 1) | (voodoo->params.stipple >> 31); + if (!(voodoo->params.stipple & 0x80000000)) { + goto skip_pixel; + } + } + } + if (params->fbzMode & FBZ_DEPTH_ENABLE) { uint16_t old_depth = *(uint16_t *) (&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]); diff --git a/src/video/vid_voodoo_fifo.c b/src/video/vid_voodoo_fifo.c index 4530e6b01e6..c0fcfe3498b 100644 --- a/src/video/vid_voodoo_fifo.c +++ b/src/video/vid_voodoo_fifo.c @@ -62,8 +62,97 @@ voodoo_fifo_log(const char *fmt, ...) #define WAKE_DELAY_DEFAULT (TIMER_USEC * 100) -/* Per-card wake delay: Voodoo1 uses a larger delay to reduce FIFO wake frequency */ -#define WAKE_DELAY_OF(v) ((v)->type == VOODOO_1 ? (TIMER_USEC * 2000) : WAKE_DELAY_DEFAULT) +/* Per-card wake delay: keep all Voodoo cards at the default */ +#define WAKE_DELAY_OF(v) (WAKE_DELAY_DEFAULT) + +static __inline uint8_t +voodoo_queue_color_buf_tag(const voodoo_t *voodoo, int buf) +{ + if (buf == voodoo->queued_disp_buffer) + return VOODOO_BUF_FRONT; + if (buf == voodoo->queued_draw_buffer) + return VOODOO_BUF_BACK; + return VOODOO_BUF_UNKNOWN; +} + +static __inline void +voodoo_queue_recalc_buffers(voodoo_t *voodoo) +{ + switch (voodoo->queued_lfbMode & LFB_WRITE_MASK) { + case LFB_WRITE_FRONT: + voodoo->queued_fb_write_buffer = voodoo->queued_disp_buffer; + break; + case LFB_WRITE_BACK: + voodoo->queued_fb_write_buffer = voodoo->queued_draw_buffer; + break; + default: + voodoo->queued_fb_write_buffer = voodoo->queued_disp_buffer; + break; + } + + switch (voodoo->queued_fbzMode & FBZ_DRAW_MASK) { + case FBZ_DRAW_FRONT: + voodoo->queued_fb_draw_buffer = voodoo->queued_disp_buffer; + break; + case FBZ_DRAW_BACK: + voodoo->queued_fb_draw_buffer = voodoo->queued_draw_buffer; + break; + default: + voodoo->queued_fb_draw_buffer = voodoo->queued_draw_buffer; + break; + } +} + +static __inline void +voodoo_queue_apply_reg(voodoo_t *voodoo, uint32_t addr, uint32_t val) +{ + switch (addr & 0x3fc) { + case SST_lfbMode: + voodoo->queued_lfbMode = val; + voodoo_queue_recalc_buffers(voodoo); + break; + case SST_fbzMode: + voodoo->queued_fbzMode = val; + voodoo_queue_recalc_buffers(voodoo); + break; + case SST_swapbufferCMD: + if (TRIPLE_BUFFER) { + voodoo->queued_disp_buffer = (voodoo->queued_disp_buffer + 1) % 3; + voodoo->queued_draw_buffer = (voodoo->queued_draw_buffer + 1) % 3; + } else { + voodoo->queued_disp_buffer = !voodoo->queued_disp_buffer; + voodoo->queued_draw_buffer = !voodoo->queued_draw_buffer; + } + voodoo_queue_recalc_buffers(voodoo); + break; + default: + break; + } +} + +static __inline uint8_t +voodoo_queue_reg_target_buf(voodoo_t *voodoo, uint32_t addr) +{ + switch (addr & 0x3fc) { + case SST_triangleCMD: + case SST_ftriangleCMD: + case SST_fastfillCMD: + return voodoo_queue_color_buf_tag(voodoo, voodoo->queued_fb_draw_buffer); + case SST_lfbMode: + case SST_fbzMode: + case SST_swapbufferCMD: + return VOODOO_BUF_UNKNOWN; + default: + return VOODOO_BUF_NONE; + } +} + +static __inline void +voodoo_cmdfifo_reg_writel(voodoo_t *voodoo, uint32_t addr, uint32_t val) +{ + voodoo_reg_writel(addr, val, voodoo); + voodoo_queue_apply_reg(voodoo, addr, val); +} void voodoo_wake_fifo_thread(voodoo_t *voodoo) { @@ -94,8 +183,19 @@ void voodoo_queue_command(voodoo_t *voodoo, uint32_t addr_type, uint32_t val) { fifo_entry_t *fifo = &voodoo->fifo[voodoo->fifo_write_idx & FIFO_MASK]; + uint64_t fifo_wait_start = 0; + uint64_t fifo_wait_spins = 0; + int fifo_wait_active = 0; while (FIFO_FULL) { + if (voodoo->wait_stats_enabled) { + if (!fifo_wait_active) { + fifo_wait_active = 1; + fifo_wait_start = plat_timer_read(); + voodoo->fifo_full_waits++; + } + fifo_wait_spins++; + } thread_reset_event(voodoo->fifo_not_full_event); if (FIFO_FULL) { thread_wait_event(voodoo->fifo_not_full_event, 1); /*Wait for room in ringbuffer*/ @@ -104,8 +204,38 @@ voodoo_queue_command(voodoo_t *voodoo, uint32_t addr_type, uint32_t val) } } - fifo->val = val; - fifo->addr_type = addr_type; + if (fifo_wait_active) { + voodoo->fifo_full_wait_ticks += plat_timer_read() - fifo_wait_start; + voodoo->fifo_full_spin_checks += fifo_wait_spins; + } + +#ifdef _WIN32 + /* Reset only after an empty signal to avoid heavy ResetEvent churn on Windows. */ + if (ATOMIC_LOAD(voodoo->fifo_empty_signaled)) { + ATOMIC_STORE(voodoo->fifo_empty_signaled, 0); + thread_reset_event(voodoo->fifo_empty_event); + } +#else + thread_reset_event(voodoo->fifo_empty_event); +#endif + + fifo->val = val; + fifo->addr_type = addr_type; + fifo->target_buf = VOODOO_BUF_NONE; + + if (((addr_type & FIFO_TYPE) == FIFO_WRITEW_FB) || + ((addr_type & FIFO_TYPE) == FIFO_WRITEL_FB)) { + fifo->target_buf = voodoo_queue_color_buf_tag(voodoo, voodoo->queued_fb_write_buffer); + ATOMIC_INC(voodoo->pending_fb_writes_buf[fifo->target_buf]); + } else if ((addr_type & FIFO_TYPE) == FIFO_WRITEL_REG) { + uint8_t reg_buf = voodoo_queue_reg_target_buf(voodoo, addr_type & FIFO_ADDR); + + if (reg_buf != VOODOO_BUF_NONE) { + fifo->target_buf = reg_buf; + ATOMIC_INC(voodoo->pending_draw_cmds_buf[fifo->target_buf]); + } + voodoo_queue_apply_reg(voodoo, addr_type & FIFO_ADDR, val); + } voodoo->fifo_write_idx++; voodoo->cmd_status &= ~(1 << 24); @@ -120,7 +250,7 @@ voodoo_flush(voodoo_t *voodoo) voodoo->flush = 1; while (!FIFO_EMPTY) { voodoo_wake_fifo_thread_now(voodoo); - thread_wait_event(voodoo->fifo_not_full_event, 1); + thread_wait_event(voodoo->fifo_empty_event, -1); } voodoo_wait_for_render_thread_idle(voodoo); voodoo->flush = 0; @@ -138,9 +268,7 @@ void voodoo_wait_for_swap_complete(voodoo_t *voodoo) { while (voodoo->swap_pending) { - thread_wait_event(voodoo->wake_fifo_thread, -1); - thread_reset_event(voodoo->wake_fifo_thread); - + /* Avoid waiting on wake_fifo_thread here; main thread may be draining the FIFO. */ thread_wait_mutex(voodoo->swap_mutex); if ((voodoo->swap_pending && voodoo->flush) || FIFO_FULL) { /*Main thread is waiting for FIFO to empty, so skip vsync wait and just swap*/ @@ -153,6 +281,13 @@ voodoo_wait_for_swap_complete(voodoo_t *voodoo) break; } else thread_release_mutex(voodoo->swap_mutex); + /* Yield briefly while waiting for the swap to complete. */ +#ifdef _WIN32 + /* Sleep(1) can add measurable stalls on Windows. */ + plat_delay_ms(0); +#else + plat_delay_ms(1); +#endif } } @@ -261,9 +396,15 @@ voodoo_fifo_thread(void *param) switch (fifo->addr_type & FIFO_TYPE) { case FIFO_WRITEL_REG: while ((fifo->addr_type & FIFO_TYPE) == FIFO_WRITEL_REG) { - voodoo_reg_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); + uint32_t reg_addr = fifo->addr_type & FIFO_ADDR; + uint8_t target_buf = fifo->target_buf; + + voodoo_reg_writel(reg_addr, fifo->val, voodoo); fifo->addr_type = FIFO_INVALID; voodoo->fifo_read_idx++; + if (target_buf < VOODOO_BUF_COUNT) { + ATOMIC_DEC(voodoo->pending_draw_cmds_buf[target_buf]); + } if (FIFO_EMPTY) break; fifo = &voodoo->fifo[voodoo->fifo_read_idx & FIFO_MASK]; @@ -272,9 +413,14 @@ voodoo_fifo_thread(void *param) case FIFO_WRITEW_FB: voodoo_wait_for_render_thread_idle(voodoo); while ((fifo->addr_type & FIFO_TYPE) == FIFO_WRITEW_FB) { + uint8_t target_buf = fifo->target_buf; + voodoo_fb_writew(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); fifo->addr_type = FIFO_INVALID; voodoo->fifo_read_idx++; + if (target_buf < VOODOO_BUF_COUNT) { + ATOMIC_DEC(voodoo->pending_fb_writes_buf[target_buf]); + } if (FIFO_EMPTY) break; fifo = &voodoo->fifo[voodoo->fifo_read_idx & FIFO_MASK]; @@ -283,9 +429,14 @@ voodoo_fifo_thread(void *param) case FIFO_WRITEL_FB: voodoo_wait_for_render_thread_idle(voodoo); while ((fifo->addr_type & FIFO_TYPE) == FIFO_WRITEL_FB) { + uint8_t target_buf = fifo->target_buf; + voodoo_fb_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); fifo->addr_type = FIFO_INVALID; voodoo->fifo_read_idx++; + if (target_buf < VOODOO_BUF_COUNT) { + ATOMIC_DEC(voodoo->pending_fb_writes_buf[target_buf]); + } if (FIFO_EMPTY) break; fifo = &voodoo->fifo[voodoo->fifo_read_idx & FIFO_MASK]; @@ -326,6 +477,8 @@ voodoo_fifo_thread(void *param) voodoo->cmd_status |= (1 << 24); voodoo->cmd_status_2 |= (1 << 24); + thread_set_event(voodoo->fifo_empty_event); + ATOMIC_STORE(voodoo->fifo_empty_signaled, 1); while (voodoo->cmdfifo_enabled && (voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr || voodoo->cmdfifo_in_sub)) { uint64_t start_time = plat_timer_read(); @@ -418,7 +571,7 @@ voodoo_fifo_thread(void *param) if (voodoo->type >= VOODOO_BANSHEE && (addr & 0x3ff) == SST_swapbufferCMD) voodoo->cmd_written_fifo++; - voodoo_reg_writel(addr, val, voodoo); + voodoo_cmdfifo_reg_writel(voodoo, addr, val); } if (header & (1 << 15)) @@ -447,7 +600,7 @@ voodoo_fifo_thread(void *param) num = (header >> 29) & 7; mask = header; //(header >> 10) & 0xff; smode = (header >> 22) & 0xf; - voodoo_reg_writel(SST_sSetupMode, ((header >> 10) & 0xff) | (smode << 16), voodoo); + voodoo_cmdfifo_reg_writel(voodoo, SST_sSetupMode, ((header >> 10) & 0xff) | (smode << 16)); num_verticies = (header >> 6) & 0xf; v_num = 0; if (((header >> 3) & 7) == 2) @@ -492,9 +645,9 @@ voodoo_fifo_thread(void *param) voodoo->verts[3].sT1 = cmdfifo_get_f(voodoo); } if (v_num) - voodoo_reg_writel(SST_sDrawTriCMD, 0, voodoo); + voodoo_cmdfifo_reg_writel(voodoo, SST_sDrawTriCMD, 0); else - voodoo_reg_writel(SST_sBeginTriCMD, 0, voodoo); + voodoo_cmdfifo_reg_writel(voodoo, SST_sBeginTriCMD, 0); v_num++; if (v_num == 3 && ((header >> 3) & 7) == 0) v_num = 0; @@ -528,7 +681,7 @@ voodoo_fifo_thread(void *param) if (voodoo->type >= VOODOO_BANSHEE && (addr & 0x3ff) == SST_swapbufferCMD) voodoo->cmd_written_fifo++; - voodoo_reg_writel(addr, val, voodoo); + voodoo_cmdfifo_reg_writel(voodoo, addr, val); } } @@ -709,7 +862,7 @@ voodoo_fifo_thread(void *param) if (voodoo->type >= VOODOO_BANSHEE && (addr & 0x3ff) == SST_swapbufferCMD) voodoo->cmd_written_fifo_2++; - voodoo_reg_writel(addr, val, voodoo); + voodoo_cmdfifo_reg_writel(voodoo, addr, val); } if (header & (1 << 15)) @@ -738,7 +891,7 @@ voodoo_fifo_thread(void *param) num = (header >> 29) & 7; mask = header; //(header >> 10) & 0xff; smode = (header >> 22) & 0xf; - voodoo_reg_writel(SST_sSetupMode, ((header >> 10) & 0xff) | (smode << 16), voodoo); + voodoo_cmdfifo_reg_writel(voodoo, SST_sSetupMode, ((header >> 10) & 0xff) | (smode << 16)); num_verticies = (header >> 6) & 0xf; v_num = 0; if (((header >> 3) & 7) == 2) @@ -783,9 +936,9 @@ voodoo_fifo_thread(void *param) voodoo->verts[3].sT1 = cmdfifo_get_f_2(voodoo); } if (v_num) - voodoo_reg_writel(SST_sDrawTriCMD, 0, voodoo); + voodoo_cmdfifo_reg_writel(voodoo, SST_sDrawTriCMD, 0); else - voodoo_reg_writel(SST_sBeginTriCMD, 0, voodoo); + voodoo_cmdfifo_reg_writel(voodoo, SST_sBeginTriCMD, 0); v_num++; if (v_num == 3 && ((header >> 3) & 7) == 0) v_num = 0; @@ -819,7 +972,7 @@ voodoo_fifo_thread(void *param) if (voodoo->type >= VOODOO_BANSHEE && (addr & 0x3ff) == SST_swapbufferCMD) voodoo->cmd_written_fifo_2++; - voodoo_reg_writel(addr, val, voodoo); + voodoo_cmdfifo_reg_writel(voodoo, addr, val); } } diff --git a/src/video/vid_voodoo_render.c b/src/video/vid_voodoo_render.c index 9c1204bd398..1c0edf77516 100644 --- a/src/video/vid_voodoo_render.c +++ b/src/video/vid_voodoo_render.c @@ -88,6 +88,8 @@ typedef struct voodoo_state_t { uint32_t texBaseAddr; int lod_frac[2]; + + int stipple; } voodoo_state_t; #ifdef ENABLE_VOODOO_RENDER_LOG @@ -932,7 +934,7 @@ voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t * state->x = x; state->x2 = x2; #ifndef NO_CODEGEN - if (voodoo->use_recompiler) { + if (voodoo->use_recompiler && voodoo_draw) { voodoo_draw(state, params, x, real_y); } else #endif @@ -990,6 +992,20 @@ voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t * w_depth = 0xffff; } + if (params->fbzMode & FBZ_STIPPLE) { + if (params->fbzMode & FBZ_STIPPLE_PATT) { + int index = ((real_y & 3) << 3) | (~x & 7); + + if (!(state->stipple & (1 << index))) + goto skip_pixel; + } else { + state->stipple = (state->stipple << 1) | (state->stipple >> 31); + if (!(state->stipple & 0x80000000)) { + goto skip_pixel; + } + } + } + #if 0 w_depth = CLAMP16(w_depth); #endif @@ -1017,6 +1033,13 @@ voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t * dest_b |= (dest_b >> 5); dest_a = 0xff; + if (params->fbzMode & FBZ_ALPHA_ENABLE) { + if (voodoo->params.aux_tiled) + dest_a = aux_mem[x_tiled]; + else + dest_a = aux_mem[x]; + } + if (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) { if ((params->textureMode[0] & TEXTUREMODE_LOCAL_MASK) == TEXTUREMODE_LOCAL || !voodoo->dual_tmus) { /*TMU0 only sampling local colour or only one TMU, only sample TMU0*/ @@ -1032,11 +1055,6 @@ voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t * } else { voodoo_tmu_fetch_and_blend(voodoo, params, state, x); } - - if ((params->fbzMode & FBZ_CHROMAKEY) && state->tex_r[0] == params->chromaKey_r && state->tex_g[0] == params->chromaKey_g && state->tex_b[0] == params->chromaKey_b) { - voodoo->fbiChromaFail++; - goto skip_pixel; - } } if (voodoo->trexInit1[0] & (1 << 18)) { @@ -1088,6 +1106,11 @@ voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t * break; } + if ((params->fbzMode & FBZ_CHROMAKEY) && cother_r == params->chromaKey_r && cother_g == params->chromaKey_g && cother_b == params->chromaKey_b) { + voodoo->fbiChromaFail++; + goto skip_pixel; + } + switch (cca_localselect) { case CCA_LOCALSELECT_ITER_A: alocal = CLAMP(state->ia >> 12); @@ -1123,6 +1146,10 @@ voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t * break; } + if ((params->fbzMode & FBZ_ALPHA_MASK) && !(aother & 1)) { + goto skip_pixel; + } + if (cc_zero_other) { src_r = 0; src_g = 0; @@ -1283,6 +1310,9 @@ voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t * dest_b = dithersub_rb2x2[dest_b][real_y & 1][x & 1]; } ALPHA_BLEND(src_r, src_g, src_b, src_a); + + // TODO: Implement proper alpha blending support here for alpha values. + src_a = (((dest_aafunc == 4) ? dest_a * 256 : 0) + ((src_aafunc == 4) ? src_a * 256 : 0)) >> 8; } if (update) { @@ -1308,7 +1338,13 @@ voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t * else fb_mem[x] = src_b | (src_g << 5) | (src_r << 11); } - if ((params->fbzMode & (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) == (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) { + if ((params->fbzMode & (FBZ_DEPTH_WMASK | FBZ_ALPHA_ENABLE)) == (FBZ_DEPTH_WMASK | FBZ_ALPHA_ENABLE)) { + if (voodoo->params.aux_tiled) + aux_mem[x_tiled] = src_a; + else + aux_mem[x] = src_a; + } + else if ((params->fbzMode & (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) == (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) { if (voodoo->params.aux_tiled) aux_mem[x_tiled] = new_depth; else @@ -1353,8 +1389,10 @@ voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t * voodoo->texel_count[odd_even] += state->texel_count; voodoo->fbiPixelsIn += state->pixel_count; - if (voodoo->params.draw_offset == voodoo->params.front_offset && (real_y >> 1) < 2048) - voodoo->dirty_line[real_y >> 1] = 1; + if (voodoo->params.draw_offset == voodoo->params.front_offset && !SLI_ENABLED) { + if (real_y < 2048) + voodoo->dirty_line[real_y] = 1; + } next_line: if (SLI_ENABLED) { @@ -1540,6 +1578,7 @@ voodoo_render_log("voodoo_triangle %i %i %i : vA %f, %f vB %f, %f vC %f, %f f if (lodbias & 0x20) lodbias |= ~0x3f; state.tmu[1].lod = LOD + (lodbias << 6); + state.stipple = params->stipple; voodoo_half_triangle(voodoo, params, &state, vertexAy_adjusted, vertexCy_adjusted, odd_even); } diff --git a/src/video/vid_wy700.c b/src/video/vid_wy700.c index bd9ba93862f..0245b7e3eec 100644 --- a/src/video/vid_wy700.c +++ b/src/video/vid_wy700.c @@ -886,7 +886,7 @@ wy700_init(UNUSED(const device_t *info)) /* 128k video RAM */ wy700->vram = malloc(0x20000); - loadfont("roms/video/wyse700/wy700.rom", 3); + video_load_font("roms/video/wyse700/wy700.rom", FONT_FORMAT_WY700, LOAD_FONT_NO_OFFSET); timer_add(&wy700->timer, wy700_poll, wy700, 1); diff --git a/src/video/video.c b/src/video/video.c index 81fe3a26b92..c1d09627038 100644 --- a/src/video/video.c +++ b/src/video/video.c @@ -8,37 +8,8 @@ * * Main video-rendering module. * - * Video timing settings - - * - * 8-bit - 1mb/sec - * B = 8 ISA clocks - * W = 16 ISA clocks - * L = 32 ISA clocks - * - * Slow 16-bit - 2mb/sec - * B = 6 ISA clocks - * W = 8 ISA clocks - * L = 16 ISA clocks - * - * Fast 16-bit - 4mb/sec - * B = 3 ISA clocks - * W = 3 ISA clocks - * L = 6 ISA clocks - * - * Slow VLB/PCI - 8mb/sec (ish) - * B = 4 bus clocks - * W = 8 bus clocks - * L = 16 bus clocks - * - * Mid VLB/PCI - - * B = 4 bus clocks - * W = 5 bus clocks - * L = 10 bus clocks - * - * Fast VLB/PCI - - * B = 3 bus clocks - * W = 3 bus clocks - * L = 4 bus clocks + * Video timings are set individually by the graphics cards. + * * * Authors: Sarah Walker, * Miran Grca, @@ -79,8 +50,6 @@ uint8_t edatlookup[4][4]; uint8_t egaremap2bpp[256]; uint8_t fontdat[2048][8]; /* IBM CGA font */ uint8_t fontdatm[2048][16]; /* IBM MDA font */ -uint8_t fontdat2[2048][8]; /* IBM CGA 2nd instance font */ -uint8_t fontdatm2[2048][16]; /* IBM MDA 2nd instance font */ uint8_t fontdatw[512][32]; /* Wyse700 font */ uint8_t fontdat8x12[256][16]; /* MDSI Genius font */ uint8_t fontdat12x18[256][36]; /* IM1024 font */ @@ -407,7 +376,7 @@ video_screenshot_monitor(uint32_t *buf, int start_x, int start_y, int row_len, i video_take_screenshot_monitor((const char *) path, buf, start_x, start_y, row_len, monitor_index); png_destroy_write_struct(&png_ptr[monitor_index], &info_ptr[monitor_index]); - atomic_fetch_sub(&monitors[monitor_index].mon_screenshots, 1); + atomic_fetch_sub(&monitors[monitor_index].mon_screenshots_raw, 1); } void @@ -793,30 +762,6 @@ hline(bitmap_t *b, int x1, int y, int x2, uint32_t col) b->line[y][x] = col; } -void -blit(UNUSED(bitmap_t *src), UNUSED(bitmap_t *dst), UNUSED(int x1), UNUSED(int y1), UNUSED(int x2), UNUSED(int y2), UNUSED(int xs), UNUSED(int ys)) -{ - // -} - -void -stretch_blit(UNUSED(bitmap_t *src), UNUSED(bitmap_t *dst), UNUSED(int x1), UNUSED(int y1), UNUSED(int xs1), UNUSED(int ys1), UNUSED(int x2), UNUSED(int y2), UNUSED(int xs2), UNUSED(int ys2)) -{ - // -} - -void -rectfill(UNUSED(bitmap_t *b), UNUSED(int x1), UNUSED(int y1), UNUSED(int x2), UNUSED(int y2), UNUSED(uint32_t col)) -{ - // -} - -void -set_palette(UNUSED(PALETTE p)) -{ - // -} - void destroy_bitmap(bitmap_t *b) { @@ -869,6 +814,9 @@ video_monitor_init(int index) monitors[index].mon_vid_type = VIDEO_FLAG_TYPE_NONE; atomic_init(&doresize_monitors[index], 0); atomic_init(&monitors[index].mon_screenshots, 0); + atomic_init(&monitors[index].mon_screenshots_clipboard, 0); + atomic_init(&monitors[index].mon_screenshots_raw, 0); + atomic_init(&monitors[index].mon_screenshots_raw_clipboard, 0); if (index >= 1) ui_init_monitor(index); monitors[index].mon_blit_data_ptr->blit_thread = thread_create(blit_thread, monitors[index].mon_blit_data_ptr); @@ -1005,10 +953,18 @@ video_force_resize_set_monitor(uint8_t res, int monitor_index) } void -loadfont_common(FILE *fp, int format) +video_load_font(char *fn, int format, int offset) { + FILE *fp; + + fp = rom_fopen(fn, "rb"); + if (fp == NULL) + return; + + fseek(fp, offset, SEEK_SET); + switch (format) { - case 0: /* MDA */ + case FONT_FORMAT_MDA: /* MDA */ for (uint16_t c = 0; c < 256; c++) /* 8x14 MDA in 8x8 cell (lines 0-7) */ for (uint8_t d = 0; d < 8; d++) fontdatm[c][d] = fgetc(fp) & 0xff; @@ -1021,7 +977,7 @@ loadfont_common(FILE *fp, int format) fontdat[c][d] = fgetc(fp) & 0xff; break; - case 1: /* PC200 */ + case FONT_FORMAT_PC200: /* PC200 */ for (uint8_t d = 0; d < 4; d++) { /* There are 4 fonts in the ROM */ for (uint16_t c = 0; c < 256; c++) /* 8x14 MDA in 8x16 cell */ @@ -1033,26 +989,25 @@ loadfont_common(FILE *fp, int format) } break; - default: - case 2: /* CGA */ + case FONT_FORMAT_CGA: /* CGA */ for (uint16_t c = 0; c < 256; c++) for (uint8_t d = 0; d < 8; d++) fontdat[c][d] = fgetc(fp) & 0xff; break; - case 3: /* Wyse 700 */ + case FONT_FORMAT_WY700: /* Wyse 700 */ for (uint16_t c = 0; c < 512; c++) for (uint8_t d = 0; d < 32; d++) fontdatw[c][d] = fgetc(fp) & 0xff; break; - case 4: /* MDSI Genius */ + case FONT_FORMAT_MDSI_GENIUS: /* MDSI Genius */ for (uint16_t c = 0; c < 256; c++) for (uint8_t d = 0; d < 16; d++) fontdat8x12[c][d] = fgetc(fp) & 0xff; break; - case 5: /* Toshiba 3100e */ + case FONT_FORMAT_TOSHIBA_3100E: /* Toshiba 3100e */ for (uint16_t d = 0; d < 2048; d += 512) { /* Four languages... */ for (uint16_t c = d; c < d + 256; c++) { (void) !fread(&fontdatm[c][8], 1, 8, fp); @@ -1076,7 +1031,7 @@ loadfont_common(FILE *fp, int format) } break; - case 6: /* Korean KSC-5601 */ + case FONT_FORMAT_KSC6501: /* Korean KSC-5601 */ if (!fontdatksc5601) fontdatksc5601 = malloc(16384 * sizeof(dbcs_font_t)); @@ -1089,7 +1044,7 @@ loadfont_common(FILE *fp, int format) } break; - case 7: /* Sigma Color 400 */ + case FONT_FORMAT_SIGMA: /* Sigma Color 400 */ /* The first 4k of the character ROM holds an 8x8 font */ for (uint16_t c = 0; c < 256; c++) { (void) !fread(&fontdat[c][0], 1, 8, fp); @@ -1098,62 +1053,32 @@ loadfont_common(FILE *fp, int format) /* The second 4k holds an 8x16 font */ for (uint16_t c = 0; c < 256; c++) { if (fread(&fontdatm[c][0], 1, 16, fp) != 16) - fatal("loadfont(): Error reading 8x16 font in Sigma Color 400 mode, c = %i\n", c); + fatal("video_load_font(): Error reading 8x16 font in Sigma Color 400 mode, c = %i\n", c); } break; - case 8: /* Amstrad PC1512, Toshiba T1000/T1200 */ + case FONT_FORMAT_PC1512_T1000: /* Amstrad PC1512, Toshiba T1000/T1200 */ for (uint16_t c = 0; c < 2048; c++) /* Allow up to 2048 chars */ for (uint8_t d = 0; d < 8; d++) fontdat[c][d] = fgetc(fp) & 0xff; break; - case 9: /* Image Manager 1024 native font */ + case FONT_FORMAT_IM1024: /* Image Manager 1024 native font */ for (uint16_t c = 0; c < 256; c++) (void) !fread(&fontdat12x18[c][0], 1, 36, fp); break; - case 10: /* Pravetz */ + case FONT_FORMAT_PRAVETZ: /* Pravetz */ for (uint16_t c = 0; c < 1024; c++) /* Allow up to 1024 chars */ for (uint8_t d = 0; d < 8; d++) fontdat[c][d] = fgetc(fp) & 0xff; break; - case 11: /* PC200 */ - for (uint8_t d = 0; d < 4; d++) { - /* There are 4 fonts in the ROM */ - for (uint16_t c = 0; c < 256; c++) /* 8x14 MDA in 8x16 cell */ - (void) !fread(&fontdatm2[256 * d + c][0], 1, 16, fp); - for (uint16_t c = 0; c < 256; c++) { /* 8x8 CGA in 8x16 cell */ - (void) !fread(&fontdat2[256 * d + c][0], 1, 8, fp); - fseek(fp, 8, SEEK_CUR); - } - } - break; } (void) fclose(fp); } -void -loadfont_ex(char *fn, int format, int offset) -{ - FILE *fp; - - fp = rom_fopen(fn, "rb"); - if (fp == NULL) - return; - - fseek(fp, offset, SEEK_SET); - loadfont_common(fp, format); -} - -void -loadfont(char *fn, int format) -{ - loadfont_ex(fn, format, 0); -} - uint32_t video_color_transform(uint32_t color) { diff --git a/vcpkg.json b/vcpkg.json index 6a4f6376cb8..4c0d502ef14 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,6 +1,6 @@ { "name": "86box", - "version-string": "6.0", + "version-string": "5.4", "homepage": "https://86box.net/", "documentation": "https://86box.readthedocs.io/", "license": "GPL-2.0-or-later",