diff --git a/.ci/AppImageBuilder.yml b/.ci/AppImageBuilder.yml index be2a7f1c1..05a7b8fcb 100644 --- a/.ci/AppImageBuilder.yml +++ b/.ci/AppImageBuilder.yml @@ -72,19 +72,22 @@ AppDir: files: exclude: - etc - - lib/udev - - opt/libc/usr/share - - usr/[a-km-rt-zA-Z]* - - usr/lib/*/libasound.so.* - - usr/lib/*.a - - usr/lib/cmake - - usr/lib/pkgconfig - - usr/s[a-gi-zA-Z]* - - usr/share/[a-hj-ln-zA-Z]* - - usr/share/i[a-bd-zA-Z]* - - usr/share/m[a-df-zA-Z]* - - usr/share/metainfo/*.metainfo.xml + - usr/[!ls]* # * except lib, local, share + - usr/lib/*/libasound.so.* # using our own ALSA can cause issues, and the API is pretty stable anyway + - usr/lib/*.a # produced by library compilation + - usr/lib/cmake # produced by library compilation + - usr/lib/pkgconfig # produced by library compilation + - usr/s[!h]* # s* except share + - usr/share/[!aim]* # * except applications, icons, metainfo + - usr/share/a[!p]* # a* except applications + - usr/share/ap[!p]* # ap* except applications + - usr/share/app[!l]* # app* except applications + - usr/share/i[!c]* # i* except icons + - usr/share/icons/[!h]* # * except hicolor + - usr/share/icons/h[!i]* # h* except hicolor + - usr/share/m[!e]* # m* except metainfo + - usr/share/metainfo/*.metainfo.xml # metainfo for libraries - var AppImage: arch: !ENV '${arch_appimage}' - file_name: '-n' # nasty hack to disable metainfo validation + file_name: !ENV '${appimage_path}' diff --git a/.ci/build.sh b/.ci/build.sh index 320451a83..38cd36c0c 100644 --- a/.ci/build.sh +++ b/.ci/build.sh @@ -136,6 +136,7 @@ package_name= arch= tarball_name= skip_archive=0 +dep_report=0 strip=0 cmake_flags= while [ $# -gt 0 ] @@ -154,6 +155,11 @@ do skip_archive=1 ;; + -p) + shift + dep_report=1 + ;; + -s) shift tarball_name="$1" @@ -166,19 +172,23 @@ do ;; *) - if echo $1 | grep -q " " - then - cmake_flag="\"$1\"" - else - cmake_flag="$1" - fi - if [ -z "$cmake_flags" ] - then - cmake_flags="$cmake_flag" - else - cmake_flags="$cmake_flags $cmake_flag" - fi - shift + # Consume remaining arguments as CMake flags. + while [ $# -gt 0 ] + do + if echo $1 | grep -q " " + then + cmake_flag="\"$1\"" + else + cmake_flag="$1" + fi + if [ -z "$cmake_flags" ] + then + cmake_flags="$cmake_flag" + else + cmake_flags="$cmake_flags $cmake_flag" + fi + shift + done ;; esac done @@ -545,8 +555,8 @@ then # Switch into the correct architecture if required. case $arch in - x86_64*) arch_mac="i386";; - *) arch_mac="$arch";; + x86_64*) arch_mac="i386"; arch_cmd="x86_64";; + *) arch_mac="$arch"; arch_cmd="$arch";; esac if [ "$(arch)" != "$arch" -a "$(arch)" != "$arch_mac" ] then @@ -556,7 +566,7 @@ then args= [ $strip -ne 0 ] && args="-t $args" [ $skip_archive -ne 0 ] && args="-n $args" - arch -"$arch" zsh -lc 'exec "'"$0"'" -b "'"$package_name"'" "'"$arch"'" '"$args""$cmake_flags" + arch -"$arch_cmd" zsh -lc 'exec "'"$0"'" -b "'"$package_name"'" "'"$arch"'" '"$args""$cmake_flags" exit $? fi echo [-] Using architecture [$(arch)] @@ -589,7 +599,21 @@ then sudo sed -i -e 's/-no-feature-vulkan/-feature-vulkan/g' "$qt5_portfile" sudo sed -i -e 's/configure.env-append MAKE=/configure.env-append VULKAN_SDK=${prefix} MAKE=/g' "$qt5_portfile" fi - sudo "$macports/bin/port" install $(cat .ci/dependencies_macports.txt) + while : + do + # Attempt to install dependencies. + sudo "$macports/bin/port" install $(cat .ci/dependencies_macports.txt) 2>&1 | tee macports.log + + # Stop if no port version activation errors were found. + stuck_dep=$(grep " cannot be built while another version of " macports.log | cut -d" " -f10) + [ -z $stuck_dep ] && break + + # Deactivate the stuck dependency and try again. + sudo "$macports/bin/port" -f deactivate $stuck_dep + done + + # Remove MacPorts error detection log. + rm -f macports.log # Save build tag to skip this later. Doing it here (once everything is # in place) is important to avoid potential issues with retried builds. @@ -609,6 +633,7 @@ else # Establish general dependencies. pkgs="cmake ninja-build pkg-config git wget p7zip-full extra-cmake-modules wayland-protocols tar gzip file appstream" + [ $dep_report -ne 0 ] && pkgs="$pkgs pax-utils" if [ "$(dpkg --print-architecture)" = "$arch_deb" ] then pkgs="$pkgs build-essential" @@ -957,7 +982,7 @@ else sdl_ss=ON fi - # Build SDL2 with video systems (and some dependencies) only if the SDL interface is used. + # Build SDL2 with video systems (and dependencies) only if the SDL interface is used. sdl_ui=OFF grep -qiE "^QT:BOOL=ON" build/CMakeCache.txt || sdl_ui=ON @@ -1024,11 +1049,18 @@ else metainfo_base=archive_tmp/usr/share/metainfo mkdir -p "$metainfo_base" cp -p "src/unix/assets/$project_id."*".xml" "$metainfo_base/$project_id.appdata.xml" + applications_base=archive_tmp/usr/share/applications + mkdir -p "$applications_base" + cp -p "src/unix/assets/$project_id.desktop" "$applications_base/" # Archive icons. - icon_base=archive_tmp/usr/share/icons - mkdir -p "$icon_base" - cp -rp src/unix/assets/[0-9]*x[0-9]* "$icon_base/" + icon_base=archive_tmp/usr/share/icons/hicolor + for icon_size in src/unix/assets/[0-9]*x[0-9]* + do + icon_dir="$icon_base/$(basename "$icon_size")" + mkdir -p "$icon_dir" + cp -rp "$icon_size" "$icon_dir/apps" + done project_icon=$(ls "$icon_base/"[0-9]*x[0-9]*/* | head -1 | grep -oP '/\K([^/]+)(?=\.[^\.]+$)') # Archive executable, while also stripping it if requested. @@ -1088,7 +1120,7 @@ else # Generate modified AppImage metadata to suit build requirements. cat << EOF > AppImageBuilder-generated.yml -# This file is generated automatically by .ci/build.sh and will be +# This file is automatically generated by .ci/build.sh and will be # overwritten if edited. Please edit .ci/AppImageBuilder.yml instead. EOF while IFS= read line @@ -1096,7 +1128,7 @@ EOF # Skip blank or comment lines. echo "$line" | grep -qE '^(#|$)' && continue - # Parse "# if OPTION VALUE" condition lines. + # Parse "# if OPTION:TYPE=VALUE" CMake condition lines. condition=$(echo "$line" | grep -oP '# if \K(.+)') if [ -n "$condition" ] then @@ -1109,7 +1141,7 @@ EOF done < .ci/AppImageBuilder.yml # Download appimage-builder if necessary. - appimage_builder_url="https://github.com/AppImageCrafters/appimage-builder/releases/download/v0.9.2/appimage-builder-0.9.2-35e3eab-x86_64.AppImage" + appimage_builder_url="https://github.com/AppImageCrafters/appimage-builder/releases/download/v1.1.0/appimage-builder-1.1.0-$(uname -m).AppImage" appimage_builder_binary="$cache_dir/$(basename "$appimage_builder_url")" if [ ! -e "$appimage_builder_binary" ] then @@ -1125,18 +1157,23 @@ EOF ln -s "$cache_dir/appimage-builder-cache" appimage-builder-cache # Run appimage-builder in extract-and-run mode for Docker compatibility. + # --appdir is a workaround for https://github.com/AppImageCrafters/appimage-builder/issues/270 project="$project" project_id="$project_id" project_version="$project_version" project_icon="$project_icon" arch_deb="$arch_deb" \ - arch_appimage="$arch_appimage" APPIMAGE_EXTRACT_AND_RUN=1 ./appimage-builder.AppImage --recipe AppImageBuilder-generated.yml + arch_appimage="$arch_appimage" appimage_path="$cwd/$package_name.AppImage" APPIMAGE_EXTRACT_AND_RUN=1 ./appimage-builder.AppImage \ + --recipe AppImageBuilder-generated.yml --appdir "$(grep -oP '^\s+path: \K(.+)' AppImageBuilder-generated.yml)" status=$? - # Rename AppImage to the final name if the build succeeded. - if [ $status -eq 0 ] + # Remove appimage-builder binary on failure, just in case it's corrupted. + [ $status -ne 0 ] && rm -f "$appimage_builder_binary" + + # Generate library dependency report if requested. + if [ $dep_report -ne 0 ] then - mv "$project-"*".AppImage" "$cwd/$package_name.AppImage" - status=$? - else - # Remove appimage-builder binary just in case it's corrupted. - rm -f "$appimage_builder_binary" + echo '[-] Library dependency report:' + + # Run lddtree with AppImage lib directories included in the search path. + LD_LIBRARY_PATH=$(find "$(pwd)/archive_tmp" -type d -name lib -o -name lib64 | while read dir; do find "$dir" -type d; done | tr '\n' ':') \ + lddtree "archive_tmp/usr/local/bin/$project" 2>&1 | tee depreport.txt fi fi diff --git a/src/cdrom/cdrom_image_viso.c b/src/cdrom/cdrom_image_viso.c index 7d40deb26..9cac65b70 100644 --- a/src/cdrom/cdrom_image_viso.c +++ b/src/cdrom/cdrom_image_viso.c @@ -417,9 +417,36 @@ viso_fill_time(uint8_t *data, time_t time, int format, int longform) { uint8_t *p = data; struct tm *time_s = localtime(&time); - if (!time_s) - fatal("VISO: localtime(%d) = NULL\n", time); + if (!time_s) { + /* localtime will return NULL if the time_t is negative (Windows) + or way too far into 64-bit space (Linux). Fall back to epoch. */ + time_t epoch = 0; + time_s = localtime(&epoch); + if (!time_s) + fatal("VISO: localtime(0) = NULL\n"); + /* Force year clamping if the timestamp is known to be outside the supported ranges. */ + if (time < (longform ? -62135596800LL : -2208988800LL)) /* 0001-01-01 00:00:00 : 1900-01-01 00:00:00 */ + time_s->tm_year = -1901; + else if (time > (longform ? 253402300799LL : 5869583999LL)) /* 9999-12-31 23:59:59 : 2155-12-31 23:59:59 */ + time_s->tm_year = 8100; + } + + /* Clamp year to the supported ranges, and assume the + OS returns valid numbers in the other struct fields. */ + if (time_s->tm_year < (longform ? -1900 : 0)) { + time_s->tm_year = longform ? -1900 : 0; + time_s->tm_mon = time_s->tm_hour = time_s->tm_min = time_s->tm_sec = 0; + time_s->tm_mday = 1; + } else if (time_s->tm_year > (longform ? 8099 : 255)) { + time_s->tm_year = longform ? 8099 : 255; + time_s->tm_mon = 12; + time_s->tm_mday = 31; + time_s->tm_hour = 23; + time_s->tm_min = time_s->tm_sec = 59; + } + + /* Convert timestamp. */ if (longform) { p += sprintf((char *) p, "%04u%02u%02u%02u%02u%02u00", 1900 + time_s->tm_year, 1 + time_s->tm_mon, time_s->tm_mday, @@ -443,10 +470,14 @@ viso_fill_dir_record(uint8_t *data, viso_entry_t *entry, int format, int type) { uint8_t *p = data, *q, *r; - *p++ = 0; /* size (filled in later) */ - *p++ = 0; /* extended attribute length */ - VISO_SKIP(p, 8); /* sector offset */ - VISO_LBE_32(p, entry->stats.st_size); /* size (filled in later if this is a directory) */ + *p++ = 0; /* size (filled in later) */ + *p++ = 0; /* extended attribute length */ + VISO_SKIP(p, 8); /* sector offset */ + VISO_LBE_32(p, entry->stats.st_size); /* size (filled in later if this is a directory) */ +#ifdef _WIN32 + if (entry->stats.st_mtime < 0) + pclog("VISO: Warning: Windows returned st_mtime %lld on file [%s]\n", (long long) entry->stats.st_mtime, entry->path); +#endif p += viso_fill_time(p, entry->stats.st_mtime, format, 0); /* time */ *p++ = S_ISDIR(entry->stats.st_mode) ? 0x02 : 0x00; /* flags */ @@ -848,7 +879,7 @@ viso_init(const char *dirname, int *error) /* Handle file size and El Torito boot code. */ if (!S_ISDIR(entry->stats.st_mode)) { - /* Limit to 4 GB - 1 byte. */ + /* Clamp to 4 GB - 1 byte. */ if (entry->stats.st_size > ((uint32_t) -1)) entry->stats.st_size = (uint32_t) -1; diff --git a/src/chipset/ali1543.c b/src/chipset/ali1543.c index 04f3f70c8..02910ded8 100644 --- a/src/chipset/ali1543.c +++ b/src/chipset/ali1543.c @@ -751,9 +751,15 @@ ali5229_write(int func, int addr, uint8_t val, void *priv) /* Bus Mastering Base Address */ case 0x20: case 0x21: - case 0x22: - case 0x23: - dev->ide_conf[addr] = val; + /* Datasheet erratum: the PCI BAR's actually have different sizes. */ + if (addr == 0x20) + dev->ide_conf[addr] = (val & 0xe0) | 0x01; + else if ((addr & 0x43) == 0x00) + dev->ide_conf[addr] = (val & 0xf8) | 0x01; + else if ((addr & 0x43) == 0x40) + dev->ide_conf[addr] = (val & 0xfc) | 0x01; + else + dev->ide_conf[addr] = val; ali5229_ide_handler(dev); break; @@ -1568,7 +1574,7 @@ ali1543_init(const device_t *info) dev->offset = (info->local >> 8) & 0x7f; if (info->local & 0x8000) dev->offset = -dev->offset; - pclog("Offset = %i\n", dev->offset); + ali1543_log("Offset = %i\n", dev->offset); pci_enable_mirq(0); pci_enable_mirq(1); diff --git a/src/chipset/intel_piix.c b/src/chipset/intel_piix.c index 8670de9e0..7347be38e 100644 --- a/src/chipset/intel_piix.c +++ b/src/chipset/intel_piix.c @@ -1697,6 +1697,20 @@ const device_t piix_device = { .config = NULL }; +const device_t piix_no_mirq_device = { + .name = "Intel 82371FB (PIIX) (No MIRQ)", + .internal_name = "piix_no_mirq", + .flags = DEVICE_PCI, + .local = 0x122e1101, + .init = piix_init, + .close = piix_close, + .reset = piix_reset, + { .available = NULL }, + .speed_changed = piix_speed_changed, + .force_redraw = NULL, + .config = NULL +}; + const device_t piix_rev02_device = { .name = "Intel 82371FB (PIIX) (Faulty BusMastering!!)", .internal_name = "piix_rev02", diff --git a/src/codegen/codegen_accumulate_x86-64.c b/src/codegen/codegen_accumulate_x86-64.c index d2f1e0c3f..ceb751a95 100644 --- a/src/codegen/codegen_accumulate_x86-64.c +++ b/src/codegen/codegen_accumulate_x86-64.c @@ -47,8 +47,6 @@ void codegen_accumulate(int acc_reg, int delta) void codegen_accumulate_flush(void) { - intptr_t rip; - if (acc_regs[0].count) { /* To reduce the size of the generated code, we take advantage of the fact that the target offset points to _cycles within cpu_state, diff --git a/src/cpu/808x.c b/src/cpu/808x.c index eed504196..f74fcda52 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -313,7 +313,7 @@ readmemw(uint32_t s, uint16_t a) else { wait(4, 1); ret = read_mem_b(s + a); - ret |= read_mem_b(s + (is186 ? (a + 1) : (a + 1) & 0xffff)) << 8; + ret |= read_mem_b(s + ((is186 && !is_nec) ? (a + 1) : (a + 1) & 0xffff)) << 8; } return ret; @@ -385,7 +385,7 @@ writememw(uint32_t s, uint32_t a, uint16_t v) else { write_mem_b(addr, v & 0xff); wait(4, 1); - addr = s + (is186 ? (a + 1) : ((a + 1) & 0xffff)); + addr = s + ((is186 && !is_nec) ? (a + 1) : ((a + 1) & 0xffff)); write_mem_b(addr, v >> 8); } @@ -794,7 +794,7 @@ seteaq(uint64_t val) static void push(uint16_t *val) { - if (is186 && SP == 1) { + if ((is186 && !is_nec) && (SP == 1)) { writememw(ss - 1, 0, *val); SP = cpu_state.eaaddr = 0xFFFF; return; @@ -963,7 +963,7 @@ interrupt(uint16_t addr) pfq_clear(); ovr_seg = NULL; access(39, 16); - tempf = cpu_state.flags & (is_nec && cpu_state.inside_emulation_mode ? 0x8fd7 : 0x0fd7); + tempf = cpu_state.flags & ((is_nec && cpu_state.inside_emulation_mode) ? 0x8fd7 : 0x0fd7); push(&tempf); cpu_state.flags &= ~(I_FLAG | T_FLAG); access(40, 16); @@ -1405,8 +1405,7 @@ set_co_mul(int bits, int carry) { set_cf(carry); set_of(carry); - if (!is_nec) - set_zf_ex(!carry); + set_zf_ex(!carry); if (!carry) wait(1, 0); } @@ -1653,7 +1652,8 @@ execx86(int cycs) int8_t nibble_result_s; uint16_t addr, tempw, new_cs, new_ip; uint16_t tempw_int, size, tempbp, lowbound; - uint16_t highbound, regval; + uint16_t highbound, regval, orig_sp, wordtopush; + uint16_t immediate, old_flags; int bits; uint32_t dest_seg, i, carry, nibble; uint32_t srcseg, byteaddr; @@ -1666,6 +1666,7 @@ execx86(int cycs) if (!repeating) { cpu_state.oldpc = cpu_state.pc; opcode = pfq_fetchb(); + handled = 0; oldc = cpu_state.flags & C_FLAG; if (clear_lock) { in_lock = 0; @@ -1678,6 +1679,97 @@ execx86(int cycs) // pclog("[%04X:%04X] Opcode: %02X\n", CS, cpu_state.pc, opcode); if (is186) { switch (opcode) { + case 0x60: /*PUSHA/PUSH R*/ + orig_sp = SP; + wait(1, 0); + push(&AX); + push(&CX); + push(&DX); + push(&BX); + push(&orig_sp); + push(&BP); + push(&SI); + push(&DI); + handled = 1; + break; + case 0x61: /*POPA/POP R*/ + wait(9, 0); + DI = pop(); + SI = pop(); + BP = pop(); + (void) pop(); /* former orig_sp */ + BX = pop(); + DX = pop(); + CX = pop(); + AX = pop(); + handled = 1; + break; + + case 0x62: /* BOUND r/m */ + lowbound = 0; + highbound = 0; + regval = 0; + do_mod_rm(); + + lowbound = readmemw(easeg, cpu_state.eaaddr); + highbound = readmemw(easeg, cpu_state.eaaddr + 2); + regval = get_reg(cpu_reg); + if (lowbound > regval || highbound < regval) { + cpu_state.pc = cpu_state.oldpc; + interrupt(5); + } + handled = 1; + break; + + case 0x64: + case 0x65: + if (is_nec) { + /* REPC/REPNC */ + wait(1, 0); + in_rep = (opcode == 0x64 ? 1 : 2); + rep_c_flag = 1; + completed = 0; + handled = 1; + } + break; + + case 0x68: + wordtopush = pfq_fetchw(); + wait(1, 0); + push(&wordtopush); + handled = 1; + break; + + case 0x69: + immediate = 0; + bits = 16; + do_mod_rm(); + read_ea(0, 16); + immediate = pfq_fetchw(); + mul(cpu_data & 0xFFFF, immediate); + set_reg(cpu_reg, cpu_data); + set_co_mul(16, cpu_dest != 0); + handled = 1; + break; + + case 0x6a: + wordtopush = sign_extend(pfq_fetchb()); + push(&wordtopush); + handled = 1; + break; + + case 0x6b: /* IMUL reg16,reg16/mem16,imm8 */ + immediate = 0; + bits = 16; + do_mod_rm(); + read_ea(0, 16); + immediate = pfq_fetchb(); + mul(cpu_data & 0xFFFF, immediate); + set_reg(cpu_reg, cpu_data); + set_co_mul(16, cpu_dest != 0); + handled = 1; + break; + case 0x6c: case 0x6d: /* INM dst, DW/INS dst, DX */ bits = 8 << (opcode & 1); @@ -1756,28 +1848,6 @@ execx86(int cycs) handled = 1; break; - case 0xc9: /* LEAVE/DISPOSE */ - SP = BP; - BP = pop(); - handled = 1; - break; - - case 0x62: /* BOUND r/m */ - lowbound = 0; - highbound = 0; - regval = 0; - do_mod_rm(); - - lowbound = readmemw(easeg, cpu_state.eaaddr); - highbound = readmemw(easeg, cpu_state.eaaddr + 2); - regval = get_reg(cpu_reg); - if (lowbound > regval || highbound < regval) { - cpu_state.pc = cpu_state.oldpc; - interrupt(5); - } - handled = 1; - break; - case 0xc0: case 0xc1: /*rot imm8 */ bits = 8 << (opcode & 1); @@ -1867,6 +1937,12 @@ execx86(int cycs) set_ea(cpu_data); handled = 1; break; + + case 0xc9: /* LEAVE/DISPOSE */ + SP = BP; + BP = pop(); + handled = 1; + break; } } if (!handled) { @@ -1882,7 +1958,7 @@ execx86(int cycs) case 0x0F: case 0x17: case 0x1F: /* POP seg */ - if (is_nec && opcode == 0x0F) { + if (is_nec && (opcode == 0x0F)) { uint8_t orig_opcode = opcode; opcode = pfq_fetchb(); switch (opcode) { @@ -2422,34 +2498,8 @@ execx86(int cycs) break; case 0x60: /*JO alias*/ - if (is186) { /* PUSHA/PUSH R*/ - uint16_t orig_sp = SP; - wait(1, 0); - push(&AX); - push(&CX); - push(&DX); - push(&BX); - push(&orig_sp); - push(&BP); - push(&SI); - push(&DI); - } else - jcc(opcode, cpu_state.flags & V_FLAG); - break; case 0x70: /*JO*/ case 0x61: /*JNO alias*/ - if (is186) { /* POPA/POP R*/ - wait(9, 0); - DI = pop(); - SI = pop(); - BP = pop(); - (void) pop(); /* former orig_sp */ - BX = pop(); - DX = pop(); - CX = pop(); - AX = pop(); - break; - } case 0x71: /*JNO*/ jcc(opcode, cpu_state.flags & V_FLAG); break; @@ -2463,14 +2513,7 @@ execx86(int cycs) case 0x74: /*JE*/ case 0x65: /*JNE alias*/ case 0x75: /*JNE*/ - if (is_nec && (opcode & 0xFE) == 0x64) { - /* REPC/REPNC */ - wait(1, 0); - in_rep = (opcode == 0x64 ? 1 : 2); - rep_c_flag = 1; - completed = 0; - } else - jcc(opcode, cpu_state.flags & Z_FLAG); + jcc(opcode, cpu_state.flags & Z_FLAG); break; case 0x66: /*JBE alias*/ case 0x76: /*JBE*/ @@ -2479,47 +2522,14 @@ execx86(int cycs) jcc(opcode, cpu_state.flags & (C_FLAG | Z_FLAG)); break; case 0x68: /*JS alias*/ - if (is186) { /* PUSH imm16 */ - uint16_t wordtopush = pfq_fetchw(); - wait(1, 0); - push(&wordtopush); - break; - } case 0x78: /*JS*/ case 0x69: /*JNS alias*/ - if (is186 && opcode == 0x69) { /* IMUL reg16,reg16/mem16,imm16 */ - uint16_t immediate = 0; - bits = 16; - do_mod_rm(); - read_ea(0, 16); - immediate = pfq_fetchw(); - mul(cpu_data & 0xFFFF, immediate); - set_reg(cpu_reg, cpu_data); - set_co_mul(16, cpu_dest != 0); - break; - } case 0x79: /*JNS*/ jcc(opcode, cpu_state.flags & N_FLAG); break; case 0x6A: /*JP alias*/ - if (is186) { /* PUSH imm8 */ - uint16_t wordtopush = sign_extend(pfq_fetchb()); - push(&wordtopush); - break; - } case 0x7A: /*JP*/ case 0x6B: /*JNP alias*/ - if (is186 && opcode == 0x6B) { /* IMUL reg16,reg16/mem16,imm8 */ - uint16_t immediate = 0; - bits = 16; - do_mod_rm(); - read_ea(0, 16); - immediate = pfq_fetchb(); - mul(cpu_data & 0xFFFF, immediate); - set_reg(cpu_reg, cpu_data); - set_co_mul(16, cpu_dest != 0); - break; - } case 0x7B: /*JNP*/ jcc(opcode, cpu_state.flags & P_FLAG); break; @@ -2733,7 +2743,7 @@ execx86(int cycs) break; case 0x9C: /*PUSHF*/ access(33, 16); - tempw = cpu_state.flags & (is_nec && cpu_state.inside_emulation_mode ? MD_FLAG | 0x0fd7 : 0x0fd7); + tempw = cpu_state.flags & ((is_nec && cpu_state.inside_emulation_mode) ? (MD_FLAG | 0x0fd7) : 0x0fd7); push(&tempw); break; case 0x9D: /*POPF*/ @@ -3108,13 +3118,21 @@ execx86(int cycs) case 0xD4: /*AAM*/ wait(1, 0); - cpu_src = pfq_fetchb(); + if (is_nec) { + (void) pfq_fetchb(); + cpu_src = 10; + } else + cpu_src = pfq_fetchb(); if (x86_div(AL, 0)) set_pzs(16); break; case 0xD5: /*AAD*/ wait(1, 0); - mul(pfq_fetchb(), AH); + if (is_nec) { + (void) pfq_fetchb(); + mul(10, AH); + } else + mul(pfq_fetchb(), AH); cpu_dest = AL; cpu_src = cpu_data; add(8); @@ -3340,6 +3358,7 @@ execx86(int cycs) break; case 0x20: /* MUL */ case 0x28: /* IMUL */ + old_flags = cpu_state.flags; wait(1, 0); mul(get_accum(bits), cpu_data); if (opcode & 1) { @@ -3354,12 +3373,14 @@ execx86(int cycs) if (!is_nec) cpu_data = AH; } - /* NOTE: When implementing the V20, care should be taken to not change - the zero flag. */ set_sf(bits); set_pf(); if (cpu_mod != 3) wait(1, 0); + /* NOTE: When implementing the V20, care should be taken to not change + the zero flag. */ + if (is_nec) + cpu_state.flags = (cpu_state.flags & ~Z_FLAG) | (old_flags & Z_FLAG); break; case 0x30: /* DIV */ case 0x38: /* IDIV */ diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 8bb61b81a..a2c06bc1f 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -367,7 +367,7 @@ cpu_set(void) unmask_a20_in_smm = 0; CPUID = cpu_s->cpuid_model; - is8086 = (cpu_s->cpu_type > CPU_8088) && !(cpu_s->cpu_type == CPU_V20); + is8086 = (cpu_s->cpu_type > CPU_8088) && (cpu_s->cpu_type != CPU_V20) && (cpu_s->cpu_type != CPU_188); is_nec = (cpu_s->cpu_type == CPU_V20) || (cpu_s->cpu_type == CPU_V30); is186 = (cpu_s->cpu_type == CPU_186) || (cpu_s->cpu_type == CPU_188) || (cpu_s->cpu_type == CPU_V20) || (cpu_s->cpu_type == CPU_V30); is286 = (cpu_s->cpu_type >= CPU_286); diff --git a/src/cpu/cpu_table.c b/src/cpu/cpu_table.c index 97e832ed1..0e805a702 100644 --- a/src/cpu/cpu_table.c +++ b/src/cpu/cpu_table.c @@ -165,7 +165,7 @@ const cpu_family_t cpu_families[] = { {"", 0} } }, { - .package = CPU_PKG_186, + .package = CPU_PKG_8086, .manufacturer = "NEC", .name = "V30", .internal_name = "necv30", diff --git a/src/device/keyboard_xt.c b/src/device/keyboard_xt.c index 69720d9b1..2d78e1a74 100644 --- a/src/device/keyboard_xt.c +++ b/src/device/keyboard_xt.c @@ -72,7 +72,7 @@ typedef struct { int blocked; int tandy; - uint8_t pa, pb, pd; + uint8_t pa, pb, pd, clock; uint8_t key_waiting; uint8_t type, pravetz_flags; @@ -514,17 +514,22 @@ static void kbd_write(uint16_t port, uint8_t val, void *priv) { xtkbd_t *kbd = (xtkbd_t *) priv; - uint8_t bit, set; + uint8_t bit, set, new_clock; switch (port) { case 0x61: /* Keyboard Control Register (aka Port B) */ - if (!(kbd->pb & 0x40) && (val & 0x40)) { - key_queue_start = key_queue_end = 0; - kbd->want_irq = 0; - kbd->blocked = 0; - kbd_adddata(0xaa); + if (!(val & 0x80)) { + new_clock = !!(val & 0x40); + if (!kbd->clock && new_clock) { + key_queue_start = key_queue_end = 0; + kbd->want_irq = 0; + kbd->blocked = 0; + kbd_adddata(0xaa); + } } kbd->pb = val; + if (!(kbd->pb & 0x80)) + kbd->clock = !!(kbd->pb & 0x40); ppi.pb = val; timer_process(); diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 7bf834a37..8cb9fd951 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -887,6 +887,9 @@ ide_atapi_attach(ide_t *ide) ide->mdma_mode = (1 << ide->get_max(ide_boards[ide->board]->force_ata3 || !ide_bm[ide->board], TYPE_PIO)); ide->error = 1; ide->cfg_spt = ide->cfg_hpc = 0; +#ifndef EARLY_ATAPI + ide->sc->status = 0; +#endif } void @@ -1628,12 +1631,16 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), sec_count); double xfer_time = ide_get_xfer_time(ide, 512 * sec_count); wait_time = seek_time > xfer_time ? seek_time : xfer_time; - } else if (val == WIN_READ_MULTIPLE) { - sec_count = (ide->secount < ide->blocksize) ? ide->secount : ide->blocksize; + } else if ((val == WIN_READ_MULTIPLE) && (ide->blocksize > 0)) { + sec_count = ide->secount ? ide->secount : 256; + if (sec_count > ide->blocksize) + sec_count = ide->blocksize; double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), sec_count); double xfer_time = ide_get_xfer_time(ide, 512 * sec_count); wait_time = seek_time + xfer_time; - } else { + } else if ((val == WIN_READ_MULTIPLE) && (ide->blocksize == 0)) + wait_time = 200.0; + else { sec_count = 1; double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), sec_count); double xfer_time = ide_get_xfer_time(ide, 512 * sec_count); @@ -1684,9 +1691,10 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) double wait_time = seek_time > xfer_time ? seek_time : xfer_time; ide_set_callback(ide, wait_time); } else if ((ide->type == IDE_HDD) && ((val == WIN_VERIFY) || (val == WIN_VERIFY_ONCE))) { - double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), ide->secount); + uint32_t sec_count = ide->secount ? ide->secount : 256; + double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), sec_count); ide_set_callback(ide, seek_time + ide_get_xfer_time(ide, 2)); - } else if (val == WIN_IDENTIFY) + } else if ((val == WIN_IDENTIFY) || (val == WIN_SET_FEATURES)) ide_callback(ide); else ide_set_callback(ide, 200.0 * IDE_TIME); @@ -1854,7 +1862,9 @@ ide_read_data(ide_t *ide, int length) ide->atastat = BSY_STAT | READY_STAT | DSC_STAT; if (ide->command == WIN_READ_MULTIPLE) { if (!ide->blockcount) { - uint32_t sec_count = (ide->secount < ide->blocksize) ? ide->secount : ide->blocksize; + uint32_t sec_count = ide->secount ? ide->secount : 256; + if (sec_count > ide->blocksize) + sec_count = ide->blocksize; double seek_time = hdd_timing_read(&hdd[ide->hdd_num], ide_get_sector(ide), sec_count); double xfer_time = ide_get_xfer_time(ide, 512 * sec_count); ide_set_callback(ide, seek_time + xfer_time); @@ -2147,7 +2157,11 @@ ide_callback(void *priv) ide_set_signature(ide); if (ide->type == IDE_ATAPI) { +#ifdef EARLY_ATAPI ide->sc->status = DRDY_STAT | DSC_STAT; +#else + ide->sc->status = 0; +#endif ide->sc->error = 1; if (ide->device_reset) ide->device_reset(ide->sc); @@ -2443,6 +2457,8 @@ ide_callback(void *priv) case WIN_SET_MULTIPLE_MODE: if (ide->type == IDE_ATAPI) goto abort_cmd; + if ((ide->secount < 2) || (ide->secount > hdd[ide->hdd_num].max_multiple_block)) + goto abort_cmd; ide->blocksize = ide->secount; ide->atastat = DRDY_STAT | DSC_STAT; ide_irq_raise(ide); @@ -2787,6 +2803,8 @@ ide_board_setup(int board) dev->error = 1; if (dev->type != IDE_HDD) dev->cfg_spt = dev->cfg_hpc = 0; + if (dev->type == IDE_HDD) + dev->blocksize = hdd[dev->hdd_num].max_multiple_block; } } diff --git a/src/include/86box/chipset.h b/src/include/86box/chipset.h index f7ae00f87..6cd49b2f1 100644 --- a/src/include/86box/chipset.h +++ b/src/include/86box/chipset.h @@ -91,6 +91,7 @@ extern const device_t sio_device; extern const device_t sio_zb_device; extern const device_t piix_device; +extern const device_t piix_no_mirq_device; extern const device_t piix_old_device; extern const device_t piix_rev02_device; extern const device_t piix3_device; diff --git a/src/machine/m_amstrad.c b/src/machine/m_amstrad.c index 63efbed50..023f94d5b 100644 --- a/src/machine/m_amstrad.c +++ b/src/machine/m_amstrad.c @@ -2410,6 +2410,7 @@ machine_amstrad_init(const machine_t *model, int type) if (mouse_type == MOUSE_TYPE_INTERNAL) { /* Tell mouse driver about our internal mouse. */ mouse_reset(); + mouse_set_buttons(2); mouse_set_poll(ms_poll, ams); } diff --git a/src/machine/m_at_socket5.c b/src/machine/m_at_socket5.c index 3d233d41c..4e51acb47 100644 --- a/src/machine/m_at_socket5.c +++ b/src/machine/m_at_socket5.c @@ -265,7 +265,7 @@ machine_at_mb500n_init(const machine_t *model) pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); device_add(&keyboard_ps2_pci_device); device_add(&i430fx_device); - device_add(&piix_device); + device_add(&piix_no_mirq_device); device_add(&fdc37c665_device); device_add(&intel_flash_bxt_device); diff --git a/src/machine/m_at_socket7_3v.c b/src/machine/m_at_socket7_3v.c index 2827c43ef..3a7505a38 100644 --- a/src/machine/m_at_socket7_3v.c +++ b/src/machine/m_at_socket7_3v.c @@ -287,8 +287,8 @@ machine_at_fmb_init(const machine_t *model) pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 3, 2, 1); device_add(&i430fx_device); - device_add(&piix_device); - device_add(&keyboard_ps2_ami_pci_device); + device_add(&piix_no_mirq_device); + device_add(&keyboard_at_ami_device); device_add(&w83787f_device); device_add(&intel_flash_bxt_device); diff --git a/src/machine/m_v86p.c b/src/machine/m_v86p.c index 4642d6b80..5f115dab3 100644 --- a/src/machine/m_v86p.c +++ b/src/machine/m_v86p.c @@ -42,6 +42,7 @@ #include <86box/fdd.h> #include <86box/fdc.h> #include <86box/fdc_ext.h> +#include <86box/hdc.h> #include <86box/keyboard.h> #include <86box/chipset.h> #include <86box/sio.h> @@ -92,5 +93,8 @@ machine_v86p_init(const machine_t *model) if (gfxcard == VID_INTERNAL) device_add(&f82c425_video_device); + if (hdc_current <= 1) + device_add(&st506_xt_victor_v86p_device); + return ret; } diff --git a/src/machine/m_xt_olivetti.c b/src/machine/m_xt_olivetti.c index 1d53a588e..014b13d12 100644 --- a/src/machine/m_xt_olivetti.c +++ b/src/machine/m_xt_olivetti.c @@ -8,7 +8,7 @@ * * Emulation of the Olivetti XT-compatible machines. * - * + * - Supports MM58174 real-time clock emulation * * Authors: Sarah Walker, * Miran Grca, @@ -69,6 +69,28 @@ #define CGA_RGB 0 #define CGA_COMPOSITE 1 +enum MM58174_ADDR { + /* Registers */ + MM58174_TEST, /* TEST register, write only */ + MM58174_TENTHS, /* Tenths of second, read only */ + MM58174_SECOND1, /* Units of seconds, read only */ + MM58174_SECOND10, /* Tens of seconds, read only */ + MM58174_MINUTE1, + MM58174_MINUTE10, + MM58174_HOUR1, + MM58174_HOUR10, + MM58174_DAY1, + MM58174_DAY10, + MM58174_WEEKDAY, + MM58174_MONTH1, + MM58174_MONTH10, + MM58174_LEAPYEAR, /* Leap year status, write only */ + MM58174_RESET, /* RESET register, write only */ + MM58174_IRQ /* Interrupt register, read / write */ +}; + +static struct tm intclk; + typedef struct { /* Keyboard stuff. */ int wantirq; @@ -120,6 +142,170 @@ m24_log(const char *fmt, ...) # define m24_log(fmt, ...) #endif +/* Set the chip time. */ +static void +mm58174_time_set(uint8_t *regs, struct tm *tm) +{ + regs[MM58174_SECOND1] = (tm->tm_sec % 10); + regs[MM58174_SECOND10] = (tm->tm_sec / 10); + regs[MM58174_MINUTE1] = (tm->tm_min % 10); + regs[MM58174_MINUTE10] = (tm->tm_min / 10); + regs[MM58174_HOUR1] = (tm->tm_hour % 10); + regs[MM58174_HOUR10] = (tm->tm_hour / 10); + regs[MM58174_WEEKDAY] = (tm->tm_wday + 1); + regs[MM58174_DAY1] = (tm->tm_mday % 10); + regs[MM58174_DAY10] = (tm->tm_mday / 10); + regs[MM58174_MONTH1] = ((tm->tm_mon + 1) % 10); + regs[MM58174_MONTH10] = ((tm->tm_mon + 1) / 10); + /* MM87174 does not store the year, M24 uses the IRQ register to count 8 years from leap year */ + regs[MM58174_IRQ] = ((tm->tm_year + 1900) % 8); + regs[MM58174_LEAPYEAR] = 8 >> ((regs[MM58174_IRQ] & 0x07) & 0x03); +} + +/* Get the chip time. */ +#define nibbles(a) (regs[(a##1)] + 10 * regs[(a##10)]) +static void +mm58174_time_get(uint8_t *regs, struct tm *tm) +{ + tm->tm_sec = nibbles(MM58174_SECOND); + tm->tm_min = nibbles(MM58174_MINUTE); + tm->tm_hour = nibbles(MM58174_HOUR); + tm->tm_wday = (regs[MM58174_WEEKDAY] - 1); + tm->tm_mday = nibbles(MM58174_DAY); + tm->tm_mon = (nibbles(MM58174_MONTH) - 1); + /* MM87174AN does not store the year */ + tm->tm_year = (1984 + (regs[MM58174_IRQ] & 0x07) - 1900); +} + +/* One more second has passed, update the internal clock. */ +static void +mm58174_recalc() +{ + /* Ping the internal clock. */ + if (++intclk.tm_sec == 60) { + intclk.tm_sec = 0; + if (++intclk.tm_min == 60) { + intclk.tm_min = 0; + if (++intclk.tm_hour == 24) { + intclk.tm_hour = 0; + if (++intclk.tm_mday == (nvr_get_days(intclk.tm_mon, intclk.tm_year) + 1)) { + intclk.tm_mday = 1; + if (++intclk.tm_mon == 13) { + intclk.tm_mon = 1; + intclk.tm_year++; + } + } + } + } + } +} + +/* This is called every second through the NVR/RTC hook. */ +static void +mm58174_tick(nvr_t *nvr) +{ + mm58174_recalc(); + mm58174_time_set(nvr->regs, &intclk); +} + +static void +mm58174_start(nvr_t *nvr) +{ + struct tm tm; + + /* Initialize the internal and chip times. */ + if (time_sync & TIME_SYNC_ENABLED) { + /* Use the internal clock's time. */ + nvr_time_get(&tm); + mm58174_time_set(nvr->regs, &tm); + } else { + /* Set the internal clock from the chip time. */ + mm58174_time_get(nvr->regs, &tm); + nvr_time_set(&tm); + } + mm58174_time_get(nvr->regs, &intclk); +} + +/* Write to one of the chip registers. */ +static void +mm58174_write(uint16_t addr, uint8_t val, void *priv) +{ + nvr_t *nvr = (nvr_t *) priv; + + addr &= 0x0f; + val &= 0x0f; + + /* Update non-read-only changed values if not synchronizing time to host */ + if ((addr != MM58174_TENTHS) && (addr != MM58174_SECOND1) && (addr != MM58174_SECOND10)) + if ((nvr->regs[addr] != val) && !(time_sync & TIME_SYNC_ENABLED)) + nvr_dosave = 1; + + if ((addr == MM58174_RESET) && (val & 0x01)) { + /* When timer starts, MM58174 sets seconds and tenths of second to 0 */ + nvr->regs[MM58174_TENTHS] = 0; + if (!(time_sync & TIME_SYNC_ENABLED)) { + /* Only set seconds to 0 if not synchronizing time to host clock */ + nvr->regs[MM58174_SECOND1] = 0; + nvr->regs[MM58174_SECOND10] = 0; + } + } + + /* Store the new value */ + nvr->regs[addr] = val; + + /* Update internal clock with MM58174 time */ + mm58174_time_get(nvr->regs, &intclk); +} + +/* Read from one of the chip registers. */ +static uint8_t +mm58174_read(uint16_t addr, void *priv) +{ + nvr_t *nvr = (nvr_t *) priv; + + addr &= 0x0f; + + /* Set IRQ control bit to 0 upon read */ + if (addr == 0x0f) + nvr->regs[addr] &= 0x07; + + /* Grab and return the desired value */ + return (nvr->regs[addr]); +} + +/* Reset the MM58174 to a default state. */ +static void +mm58174_reset(nvr_t *nvr) +{ + /* Clear the NVRAM. */ + memset(nvr->regs, 0xff, nvr->size); + + /* Reset the RTC registers. */ + memset(nvr->regs, 0x00, 16); + nvr->regs[MM58174_WEEKDAY] = 0x01; + nvr->regs[MM58174_DAY1] = 0x01; + nvr->regs[MM58174_MONTH1] = 0x01; +} + +static void +mm58174_init(nvr_t *nvr, int size) +{ + /* This is machine specific. */ + nvr->size = size; + nvr->irq = -1; + + /* Set up any local handlers here. */ + nvr->reset = mm58174_reset; + nvr->start = mm58174_start; + nvr->tick = mm58174_tick; + + /* Initialize the actual NVR. */ + nvr_init(nvr); + + io_sethandler(0x0070, 16, + mm58174_read, NULL, NULL, mm58174_write, NULL, NULL, nvr); +} + static void m24_kbd_poll(void *priv) { @@ -426,6 +612,7 @@ m24_kbd_init(m24_kbd_t *kbd) /* Tell mouse driver about our internal mouse. */ mouse_reset(); + mouse_set_buttons(2); mouse_set_poll(ms_poll, kbd); keyboard_set_table(scancode_xt); @@ -667,7 +854,7 @@ m24_read(uint16_t port, void *priv) ret |= 0x1; break; case 256: - ret |= 0x2 | 0x80; + ret |= 0x2; break; case 384: ret |= 0x1 | 0x2 | 0x80; @@ -676,10 +863,12 @@ m24_read(uint16_t port, void *priv) ret |= 0x8; break; case 640: - default: ret |= 0x1 | 0x8 | 0x80; break; + default: + break; } + break; /* * port 67: * DIPSW-1 on mainboard (off=present=1) @@ -721,6 +910,8 @@ m24_read(uint16_t port, void *priv) /* Switch 2 - Set fast startup */ ret |= 0x2; + + break; } return (ret); @@ -731,6 +922,7 @@ machine_xt_m24_init(const machine_t *model) { int ret; m24_kbd_t *m24_kbd; + nvr_t *nvr; ret = bios_load_interleaved("roms/machines/m24/olivetti_m24_bios_version_1.44_low_even.bin", "roms/machines/m24/olivetti_m24_bios_version_1.44_high_odd.bin", @@ -751,13 +943,18 @@ machine_xt_m24_init(const machine_t *model) /* Address 66-67 = mainboard dip-switch settings */ io_sethandler(0x0066, 2, m24_read, NULL, NULL, NULL, NULL, NULL, NULL); - /* FIXME: make sure this is correct?? */ - device_add(&at_nvr_device); - standalone_gameport_type = &gameport_device; nmi_init(); + /* Allocate an NVR for this machine. */ + nvr = (nvr_t *) malloc(sizeof(nvr_t)); + if (nvr == NULL) + return (0); + memset(nvr, 0x00, sizeof(nvr_t)); + + mm58174_init(nvr, model->nvrmask + 1); + video_reset(gfxcard); if (gfxcard == VID_INTERNAL) diff --git a/src/machine/m_xt_t1000.c b/src/machine/m_xt_t1000.c index 3b45dcdcb..c467b1c91 100644 --- a/src/machine/m_xt_t1000.c +++ b/src/machine/m_xt_t1000.c @@ -103,6 +103,7 @@ #include <86box/fdd.h> #include <86box/fdc.h> #include <86box/gameport.h> +#include <86box/hdc.h> #include <86box/video.h> #include <86box/plat.h> #include <86box/machine.h> @@ -959,6 +960,9 @@ machine_xt_t1200_init(const machine_t *model) if (gfxcard == VID_INTERNAL) device_add(&t1200_video_device); + if (hdc_current <= 1) + device_add(&st506_xt_victor_v86p_device); + return ret; } diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 729935e4b..52be7a08a 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -2066,7 +2066,7 @@ const machine_t machines[] = { .max_multi = 0 }, .bus_flags = MACHINE_PC, - .flags = MACHINE_VIDEO, + .flags = MACHINE_VIDEO | MACHINE_MFM, .ram = { .min = 512, .max = 1024, @@ -2102,7 +2102,7 @@ const machine_t machines[] = { .max_multi = 0 }, .bus_flags = MACHINE_PC, - .flags = MACHINE_VIDEO, + .flags = MACHINE_VIDEO | MACHINE_MFM, .ram = { .min = 1024, .max = 2048, @@ -8263,7 +8263,7 @@ const machine_t machines[] = { .min_multi = 1.5, .max_multi = 3.0 }, - .bus_flags = MACHINE_PS2_PCI, + .bus_flags = MACHINE_PCI, .flags = MACHINE_IDE_DUAL, .ram = { .min = 8192, diff --git a/src/nvr_at.c b/src/nvr_at.c index d839295ba..174cd74e4 100644 --- a/src/nvr_at.c +++ b/src/nvr_at.c @@ -1247,29 +1247,31 @@ const device_t piix4_nvr_device = { }; const device_t ps_no_nmi_nvr_device = { - "PS/1 or PS/2 NVRAM (No NMI)", - "ps1_nvr", - DEVICE_PS2, - 10, - nvr_at_init, - nvr_at_close, - nvr_at_reset, - { NULL }, - nvr_at_speed_changed, - NULL + .name = "PS/1 or PS/2 NVRAM (No NMI)", + .internal_name = "ps1_nvr", + .flags = DEVICE_PS2, + .local = 0x10 | 2, + .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 amstrad_no_nmi_nvr_device = { - "Amstrad NVRAM (No NMI)", - "amstrad_nvr", - DEVICE_ISA | DEVICE_AT, - 11, - nvr_at_init, - nvr_at_close, - nvr_at_reset, - { NULL }, - nvr_at_speed_changed, - NULL + .name = "Amstrad NVRAM (No NMI)", + .internal_name = "amstrad_nvr", + .flags = DEVICE_ISA | DEVICE_AT, + .local = 0x10 | 3, + .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 ami_1992_nvr_device = { diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index fd2294415..2a41f4316 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -1620,7 +1620,18 @@ void MainWindow::keyPressEvent(QKeyEvent* event) if (send_keyboard_input && !(kbd_req_capture && !mouse_capture && !video_fullscreen)) { // Windows keys in Qt have one-to-one mapping. - if (event->key() == Qt::Key_Super_L || event->key() == Qt::Key_Super_R) { + if (event->key() == Qt::Key_Pause && !keyboard_recv(0x38) && !keyboard_recv(0x138)) { + if ((keyboard_recv(0x1D) || keyboard_recv(0x11D))) { + keyboard_input(1, 0x46); + } else { + keyboard_input(0, 0xE1); + keyboard_input(0, 0x1D); + keyboard_input(0, 0x45); + keyboard_input(0, 0xE1); + keyboard_input(1, 0x1D); + keyboard_input(1, 0x45); + } + } else if (event->key() == Qt::Key_Super_L || event->key() == Qt::Key_Super_R) { keyboard_input(1, event->key() == Qt::Key_Super_L ? 0x15B : 0x15C); } else #ifdef Q_OS_MACOS @@ -1637,6 +1648,12 @@ void MainWindow::keyPressEvent(QKeyEvent* event) if (keyboard_ismsexit()) { plat_mouse_capture(0); } + + if ((video_fullscreen > 0) && (keyboard_recv(0x1D) || keyboard_recv(0x11D))) { + if (keyboard_recv(0x57)) ui->actionTake_screenshot->trigger(); + else if (keyboard_recv(0x58)) pc_send_cad(); + } + event->accept(); } @@ -1651,6 +1668,11 @@ void MainWindow::blitToWidget(int x, int y, int w, int h, int monitor_index) void MainWindow::keyReleaseEvent(QKeyEvent* event) { + if (event->key() == Qt::Key_Pause) { + if (keyboard_recv(0x38) && keyboard_recv(0x138)) { + plat_pause(dopause ^ 1); + } + } if (!send_keyboard_input) return; diff --git a/src/qt/qt_mediamenu.cpp b/src/qt/qt_mediamenu.cpp index d11a14c96..bea1af22f 100644 --- a/src/qt/qt_mediamenu.cpp +++ b/src/qt/qt_mediamenu.cpp @@ -19,13 +19,15 @@ * Copyright 2021-2022 Teemu Korhonen */ #include "qt_mediamenu.hpp" - +#include "qt_progsettings.hpp" #include "qt_machinestatus.hpp" #include #include #include #include +#include +#include extern "C" { #include <86box/86box.h> @@ -123,10 +125,10 @@ void MediaMenu::refresh(QMenu *parentMenu) { MachineStatus::iterateCDROM([this, parentMenu](int i) { auto* menu = parentMenu->addMenu(""); cdromMutePos = menu->children().count(); - menu->addAction(tr("&Mute"), [this, i]() { cdromMute(i); })->setCheckable(true); + menu->addAction(QApplication::style()->standardIcon(QStyle::SP_MediaVolumeMuted), tr("&Mute"), [this, i]() { cdromMute(i); })->setCheckable(true); menu->addSeparator(); - menu->addAction(tr("&Image..."), [this, i]() { cdromMount(i, 0); })->setCheckable(false); - menu->addAction(tr("&Folder..."), [this, i]() { cdromMount(i, 1); })->setCheckable(false); + menu->addAction(ProgSettings::loadIcon("/cdrom.ico"), tr("&Image..."), [this, i]() { cdromMount(i, 0); })->setCheckable(false); + menu->addAction(QApplication::style()->standardIcon(QStyle::SP_DirIcon), tr("&Folder..."), [this, i]() { cdromMount(i, 1); })->setCheckable(false); menu->addSeparator(); for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) { cdromImageHistoryPos[slot] = menu->children().count(); @@ -478,8 +480,9 @@ void MediaMenu::cdromReload(int index, int slot) { void MediaMenu::updateImageHistory(int index, int slot, ui::MediaType type) { QMenu* menu; QAction* imageHistoryUpdatePos; - QString image_path; QObjectList children; + QFileInfo fi; + QIcon menu_icon; switch (type) { case ui::MediaType::Optical: @@ -488,7 +491,9 @@ void MediaMenu::updateImageHistory(int index, int slot, ui::MediaType type) { menu = cdromMenus[index]; children = menu->children(); imageHistoryUpdatePos = dynamic_cast(children[cdromImageHistoryPos[slot]]); - image_path = mhm.getImageForSlot(index, slot, type); + fi.setFile(mhm.getImageForSlot(index, slot, type)); + menu_icon = fi.isDir() ? QApplication::style()->standardIcon(QStyle::SP_DirIcon) : ProgSettings::loadIcon("/cdrom.ico"); + imageHistoryUpdatePos->setIcon(menu_icon); break; case ui::MediaType::Floppy: if (!floppyMenus.contains(index)) @@ -496,15 +501,15 @@ void MediaMenu::updateImageHistory(int index, int slot, ui::MediaType type) { menu = floppyMenus[index]; children = menu->children(); imageHistoryUpdatePos = dynamic_cast(children[floppyImageHistoryPos[slot]]); - image_path = mhm.getImageForSlot(index, slot, type); + fi.setFile(mhm.getImageForSlot(index, slot, type)); break; default: pclog("History not yet implemented for media type %s\n", qPrintable(mhm.mediaTypeToString(type))); return; } - QFileInfo fi(image_path); - imageHistoryUpdatePos->setText(QString::asprintf(tr("%s").toUtf8().constData(), fi.fileName().isEmpty() ? tr("previous image").toUtf8().constData() : fi.fileName().toUtf8().constData())); + QString menu_item_name = fi.fileName().isEmpty() ? tr("previous image").toUtf8().constData() : fi.fileName().toUtf8().constData(); + imageHistoryUpdatePos->setText(QString::asprintf(tr("%s").toUtf8().constData(), menu_item_name.toUtf8().constData())); imageHistoryUpdatePos->setVisible(!fi.fileName().isEmpty()); } @@ -527,7 +532,10 @@ void MediaMenu::cdromUpdateMenu(int i) { auto* imageMenu = dynamic_cast(childs[cdromImagePos]); imageMenu->setEnabled(!name.isEmpty()); - imageMenu->setText(QString::asprintf(tr("Eject %s").toUtf8().constData(), name.isEmpty() ? QString().toUtf8().constData() : fi.fileName().toUtf8().constData())); + QString menu_item_name = name.isEmpty() ? QString().toUtf8().constData() : fi.fileName().toUtf8().constData(); + auto menu_icon = fi.isDir() ? QApplication::style()->standardIcon(QStyle::SP_DirIcon) : ProgSettings::loadIcon("/cdrom.ico"); + imageMenu->setIcon(menu_icon); + imageMenu->setText(QString::asprintf(tr("Eject %s").toUtf8().constData(), menu_item_name.toUtf8().constData())); for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) { updateImageHistory(i, slot, ui::MediaType::Optical); diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index f0e5b12e0..670a0d0da 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -166,7 +166,7 @@ int ignoreNextMouseEvent = 1; void RendererStack::mouseReleaseEvent(QMouseEvent *event) { - if (this->geometry().contains(event->pos()) && event->button() == Qt::LeftButton && !mouse_capture && (isMouseDown & 1) && mouse_get_buttons() != 0) { + if (this->geometry().contains(event->pos()) && event->button() == Qt::LeftButton && !mouse_capture && (isMouseDown & 1) && (mouse_get_buttons() != 0)) { plat_mouse_capture(1); this->setCursor(Qt::BlankCursor); if (!ignoreNextMouseEvent) @@ -174,7 +174,7 @@ RendererStack::mouseReleaseEvent(QMouseEvent *event) isMouseDown &= ~1; return; } - if (mouse_capture && event->button() == Qt::MiddleButton && mouse_get_buttons() < 3) { + if (mouse_capture && (event->button() == Qt::MiddleButton) && (mouse_get_buttons() < 3)) { plat_mouse_capture(0); this->setCursor(Qt::ArrowCursor); isMouseDown &= ~1; diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index b4b91cce8..f57cfd9c5 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -349,7 +349,11 @@ scsi_cdrom_init(scsi_cdrom_t *dev) dev->sense[0] = 0xf0; dev->sense[7] = 10; +#ifdef POSSIBLE_EARLY_ATAPI dev->status = READY_STAT | DSC_STAT; +#else + dev->status = 0; +#endif dev->pos = 0; dev->packet_status = PHASE_NONE; scsi_cdrom_sense_key = scsi_cdrom_asc = scsi_cdrom_ascq = dev->unit_attention = 0; @@ -685,6 +689,7 @@ scsi_cdrom_command_complete(scsi_cdrom_t *dev) ui_sb_update_icon(SB_CDROM | dev->id, 0); dev->packet_status = PHASE_COMPLETE; scsi_cdrom_command_common(dev); + dev->phase = 3; } static void @@ -692,6 +697,7 @@ scsi_cdrom_command_read(scsi_cdrom_t *dev) { dev->packet_status = PHASE_DATA_IN; scsi_cdrom_command_common(dev); + dev->phase = !(dev->packet_status & 0x01) << 1; } static void @@ -706,6 +712,7 @@ scsi_cdrom_command_write(scsi_cdrom_t *dev) { dev->packet_status = PHASE_DATA_OUT; scsi_cdrom_command_common(dev); + dev->phase = !(dev->packet_status & 0x01) << 1; } static void @@ -1352,8 +1359,10 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) int toc_format, block_desc = 0; int ret, format = 0; int real_pos, track = 0; +#ifdef USE_86BOX_CD char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; char device_identify_ex[15] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; +#endif int32_t blen = 0, *BufLen; uint8_t *b; uint32_t profiles[2] = { MMC_PROFILE_CD_ROM, MMC_PROFILE_DVD_ROM }; @@ -1371,12 +1380,14 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) dev->packet_len = 0; dev->request_pos = 0; +#ifdef USE_86BOX_CD device_identify[7] = dev->id + 0x30; device_identify_ex[7] = dev->id + 0x30; device_identify_ex[10] = EMU_VERSION_EX[0]; device_identify_ex[12] = EMU_VERSION_EX[2]; device_identify_ex[13] = EMU_VERSION_EX[3]; +#endif memcpy(dev->current_cdb, cdb, 12); @@ -2301,16 +2312,25 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) if (dev->drv->bus_type == CDROM_BUS_SCSI) ide_padstr8(dev->buffer + idx, 8, "TOSHIBA"); /* Vendor */ else +#ifdef USE_86BOX_CD ide_padstr8(dev->buffer + idx, 8, EMU_NAME); /* Vendor */ +#else + ide_padstr8(dev->buffer + idx, 8, "HITACHI"); /* Vendor */ +#endif idx += 8; if (dev->drv->bus_type == CDROM_BUS_SCSI) ide_padstr8(dev->buffer + idx, 40, "XM6201TASUN32XCD1103"); /* Product */ else +#ifdef USE_86BOX_CD ide_padstr8(dev->buffer + idx, 40, device_identify_ex); /* Product */ +#else + ide_padstr8(dev->buffer + idx, 40, "CDR-8130"); /* Product */ +#endif idx += 40; ide_padstr8(dev->buffer + idx, 20, "53R141"); /* Product */ idx += 20; break; + default: scsi_cdrom_log("INQUIRY: Invalid page: %02X\n", cdb[2]); scsi_cdrom_invalid_field(dev); @@ -2344,9 +2364,15 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) ide_padstr8(dev->buffer + 16, 16, "XM6201TASUN32XCD"); /* Product */ ide_padstr8(dev->buffer + 32, 4, "1103"); /* Revision */ } else { +#ifdef USE_86BOX_CD ide_padstr8(dev->buffer + 8, 8, EMU_NAME); /* Vendor */ ide_padstr8(dev->buffer + 16, 16, device_identify); /* Product */ ide_padstr8(dev->buffer + 32, 4, EMU_VERSION_EX); /* Revision */ +#else + ide_padstr8(dev->buffer + 8, 8, "HITACHI"); /* Vendor */ + ide_padstr8(dev->buffer + 16, 16, "CDR-8130"); /* Product */ + ide_padstr8(dev->buffer + 32, 4, "0020"); /* Revision */ +#endif } idx = 36; @@ -2615,7 +2641,7 @@ scsi_cdrom_get_timings(int ide_has_dma, int type) static void scsi_cdrom_identify(ide_t *ide, int ide_has_dma) { -#if 0 +#ifdef USE_86BOX_CD scsi_cdrom_t *dev; char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; @@ -2627,12 +2653,17 @@ scsi_cdrom_identify(ide_t *ide, int ide_has_dma) ide->buffer[0] = 0x8000 | (5 << 8) | 0x80 | (2 << 5); /* ATAPI device, CD-ROM drive, removable media, accelerated DRQ */ ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ -#if 0 +#ifdef USE_86BOX_CD ide_padstr((char *) (ide->buffer + 23), EMU_VERSION_EX, 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ #else + #ifdef USE_NEC_CD ide_padstr((char *) (ide->buffer + 23), "4.20 ", 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "NEC CD-ROM DRIVE:273 ", 40); /* Model */ + #else + ide_padstr((char *) (ide->buffer + 23), "0020 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "HITACHI CDR-8130 ", 40); /* Model */ + #endif #endif ide->buffer[49] = 0x200; /* LBA supported */ ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 27b601f2c..1773198a6 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -534,7 +534,7 @@ MEMOBJ := catalyst_flash.o i2c_eeprom.o intel_flash.o mem.o rom.o smram.o spd.o CPUOBJ := $(DYNARECOBJ) \ $(CGTOBJ) \ cpu.o cpu_table.o fpu.o x86.o \ - 808x.o 386.o 386_common.o 386_dynarec.o 386_dynarec_ops.o \ + 8080.o 808x.o 386.o 386_common.o 386_dynarec.o 386_dynarec_ops.o \ x86seg.o x87.o x87_timings.o CHIPSETOBJ := 82c100.o acc2168.o \ diff --git a/src/win/win_settings.c b/src/win/win_settings.c index ff4eaf3b0..a1c83ca52 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -2136,12 +2136,9 @@ recalc_next_free_id(HWND hdlg) enable_add = enable_add || (next_free_id >= 0); enable_add = enable_add && ((c_mfm < MFM_NUM) || (c_esdi < ESDI_NUM) || (c_xta < XTA_NUM) || (c_ide < IDE_NUM) || (c_ide < ATAPI_NUM) || (c_scsi < SCSI_NUM)); - enable_add = enable_add && !bus_full(&mfm_tracking, 2); - enable_add = enable_add && !bus_full(&esdi_tracking, 2); - enable_add = enable_add && !bus_full(&xta_tracking, 2); - enable_add = enable_add && !bus_full(&ide_tracking, IDE_CHAN_MAX); - for (i = 0; i < 2; i++) - enable_add = enable_add && !bus_full(&(scsi_tracking[i]), 8); + enable_add = enable_add && (!bus_full(&mfm_tracking, 2) || !bus_full(&esdi_tracking, 2) || !bus_full(&xta_tracking, 2) || !bus_full(&ide_tracking, IDE_CHAN_MAX * IDE_BUS_MAX) || + !bus_full(&(scsi_tracking[0]), 8) || !bus_full(&(scsi_tracking[1]), 8) || !bus_full(&(scsi_tracking[2]), 8) || !bus_full(&(scsi_tracking[3]), 8) || + !bus_full(&(scsi_tracking[4]), 8) || !bus_full(&(scsi_tracking[5]), 8) || !bus_full(&(scsi_tracking[6]), 8) || !bus_full(&(scsi_tracking[7]), 8)); settings_enable_window(hdlg, IDC_BUTTON_HDD_ADD_NEW, enable_add); settings_enable_window(hdlg, IDC_BUTTON_HDD_ADD, enable_add);