diff --git a/.ci/build.sh b/.ci/build.sh index a53ea0671..ca77d7b83 100755 --- a/.ci/build.sh +++ b/.ci/build.sh @@ -535,6 +535,14 @@ 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 + + # Patch wget to remove libproxy support, as it depends on shared-mime-info which + # fails to build for a 10.14 target, which we have to do despite wget only being + # a host dependency. MacPorts issue 69406 strongly implies this will not be fixed. + wget_portfile="$macports/var/macports/sources/rsync.macports.org/macports/release/tarballs/ports/net/wget/Portfile" + sudo sed -i -e 's/--enable-libproxy/--disable-libproxy/g' "$wget_portfile" + sudo sed -i -e 's/port:libproxy//g' "$wget_portfile" + while : do # Attempt to install dependencies. diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d5a9dc1e..2766d4921 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -131,7 +131,6 @@ option(RTMIDI "RtMidi" option(FLUIDSYNTH "FluidSynth" ON) option(MUNT "MUNT" ON) option(VNC "VNC renderer" OFF) -option(CPPTHREADS "C++11 threads" ON) option(NEW_DYNAREC "Use the PCem v15 (\"new\") dynamic recompiler" OFF) option(MINITRACE "Enable Chrome tracing using the modified minitrace library" OFF) option(GDBSTUB "Enable GDB stub server for debugging" OFF) @@ -141,8 +140,10 @@ option(DEBUGREGS486 "Enable debug register opeartion on 486+ CPUs" if(WIN32) set(QT ON) + option(CPPTHREADS "C++11 threads" OFF) else() option(QT "Qt GUI" ON) + option(CPPTHREADS "C++11 threads" ON) endif() # Development branch features diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ad339040f..0841fabdd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,9 +27,7 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux") add_compile_definitions(_FILE_OFFSET_BITS=64 _LARGEFILE_SOURCE=1 _LARGEFILE64_SOURCE=1) endif() -if(WIN32) - target_sources(86Box PRIVATE qt/win_thread.c) -else() +if(CPPTHREADS) target_sources(86Box PRIVATE thread.cpp) endif() diff --git a/src/config.c b/src/config.c index 2c0781028..0153e20e8 100644 --- a/src/config.c +++ b/src/config.c @@ -861,16 +861,46 @@ load_storage_controllers(void) cassette_enable = !!ini_section_get_int(cat, "cassette_enabled", 0); else cassette_enable = 0; + p = ini_section_get_string(cat, "cassette_file", ""); - if (strlen(p) > 511) - fatal("load_storage_controllers(): strlen(p) > 511\n"); - else - strncpy(cassette_fname, p, 511); + + if (!strcmp(p, usr_path)) + p[0] = 0x00; + + if (p[0] != 0x00) { + if (path_abs(p)) { + if (strlen(p) > 511) + fatal("load_storage_controllers(): strlen(p) > 511 (cassette_fname)\n"); + else + strncpy(cassette_fname, p, 511); + } else + path_append_filename(cassette_fname, usr_path, p); + path_normalize(cassette_fname); + } + p = ini_section_get_string(cat, "cassette_mode", ""); if (strlen(p) > 511) fatal("load_storage_controllers(): strlen(p) > 511\n"); else strncpy(cassette_mode, p, 511); + + for (int i = 0; i < MAX_PREV_IMAGES; i++) { + cassette_image_history[i] = (char *) calloc((MAX_IMAGE_PATH_LEN + 1) << 1, sizeof(char)); + sprintf(temp, "cassette_image_history_%02i", i + 1); + p = ini_section_get_string(cat, temp, NULL); + if (p) { + if (path_abs(p)) { + if (strlen(p) > (MAX_IMAGE_PATH_LEN - 1)) + fatal("load_storage_controllers(): strlen(p) > 2047 " + "(cassette_image_history[%i])\n", i); + else + snprintf(cassette_image_history[i], (MAX_IMAGE_PATH_LEN - 1), "%s", p); + } else + snprintf(cassette_image_history[i], (MAX_IMAGE_PATH_LEN - 1), "%s%s%s", usr_path, + path_get_slash(usr_path), p); + path_normalize(cassette_image_history[i]); + } + } cassette_pos = ini_section_get_int(cat, "cassette_position", 0); cassette_srate = ini_section_get_int(cat, "cassette_srate", 44100); cassette_append = !!ini_section_get_int(cat, "cassette_append", 0); @@ -894,6 +924,24 @@ load_storage_controllers(void) path_append_filename(cart_fns[c], usr_path, p); path_normalize(cart_fns[c]); } + + for (int i = 0; i < MAX_PREV_IMAGES; i++) { + cart_image_history[c][i] = (char *) calloc((MAX_IMAGE_PATH_LEN + 1) << 1, sizeof(char)); + sprintf(temp, "cartridge_%02i_image_history_%02i", c + 1, i + 1); + p = ini_section_get_string(cat, temp, NULL); + if (p) { + if (path_abs(p)) { + if (strlen(p) > (MAX_IMAGE_PATH_LEN - 1)) + fatal("load_storage_controllers(): strlen(p) > 2047 " + "(cart_image_history[%i][%i])\n", c, i); + else + snprintf(cart_image_history[c][i], (MAX_IMAGE_PATH_LEN - 1), "%s", p); + } else + snprintf(cart_image_history[c][i], (MAX_IMAGE_PATH_LEN - 1), "%s%s%s", usr_path, + path_get_slash(usr_path), p); + path_normalize(cart_image_history[c][i]); + } + } } lba_enhancer_enabled = !!ini_section_get_int(cat, "lba_enhancer_enabled", 0); @@ -2330,14 +2378,32 @@ save_storage_controllers(void) if (strlen(cassette_fname) == 0) ini_section_delete_var(cat, "cassette_file"); - else - ini_section_set_string(cat, "cassette_file", cassette_fname); + else { + path_normalize(cassette_fname); + if (!strnicmp(cassette_fname, usr_path, strlen(usr_path))) + ini_section_set_string(cat, "cassette_file", &cassette_fname[strlen(usr_path)]); + else + ini_section_set_string(cat, "cassette_file", cassette_fname); + } if (strlen(cassette_mode) == 0) ini_section_delete_var(cat, "cassette_mode"); else ini_section_set_string(cat, "cassette_mode", cassette_mode); + for (int i = 0; i < MAX_PREV_IMAGES; i++) { + sprintf(temp, "cassette_image_history_%02i", i + 1); + if ((cassette_image_history[i] == 0) || strlen(cassette_image_history[i]) == 0) + ini_section_delete_var(cat, temp); + else { + path_normalize(cassette_image_history[i]); + if (!strnicmp(cassette_image_history[i], usr_path, strlen(usr_path))) + ini_section_set_string(cat, temp, &cassette_image_history[i][strlen(usr_path)]); + else + ini_section_set_string(cat, temp, cassette_image_history[i]); + } + } + if (cassette_pos == 0) ini_section_delete_var(cat, "cassette_position"); else @@ -2365,10 +2431,29 @@ save_storage_controllers(void) for (c = 0; c < 2; c++) { sprintf(temp, "cartridge_%02i_fn", c + 1); + if (strlen(cart_fns[c]) == 0) ini_section_delete_var(cat, temp); - else - ini_section_set_string(cat, temp, cart_fns[c]); + else { + path_normalize(cart_fns[c]); + if (!strnicmp(cart_fns[c], usr_path, strlen(usr_path))) + ini_section_set_string(cat, temp, &cart_fns[c][strlen(usr_path)]); + else + ini_section_set_string(cat, temp, cart_fns[c]); + } + + for (int i = 0; i < MAX_PREV_IMAGES; i++) { + sprintf(temp, "cartridge_%02i_image_history_%02i", c + 1, i + 1); + if ((cart_image_history[c][i] == 0) || strlen(cart_image_history[c][i]) == 0) + ini_section_delete_var(cat, temp); + else { + path_normalize(cart_image_history[c][i]); + if (!strnicmp(cart_image_history[c][i], usr_path, strlen(usr_path))) + ini_section_set_string(cat, temp, &cart_image_history[c][i][strlen(usr_path)]); + else + ini_section_set_string(cat, temp, cart_image_history[c][i]); + } + } } if (lba_enhancer_enabled == 0) diff --git a/src/cpu/386.c b/src/cpu/386.c index 3524e0d1e..50ed4fddb 100644 --- a/src/cpu/386.c +++ b/src/cpu/386.c @@ -304,6 +304,14 @@ exec386_2386(int32_t cycs) cpu_state.pc &= 0xffff; #endif + if (cpu_flush_pending == 1) + cpu_flush_pending++; + else if (cpu_flush_pending == 2) { + cpu_flush_pending = 0; + cr0 ^= 0x80000000; + flushmmucache(); + } + if (cpu_end_block_after_ins) cpu_end_block_after_ins--; diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index d8a33a624..bf8b31600 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -933,6 +933,14 @@ exec386(int32_t cycs) x386_dynarec_log("[%04X:%08X] ABRT\n", CS, cpu_state.pc); #endif + if (cpu_flush_pending == 1) + cpu_flush_pending++; + else if (cpu_flush_pending == 2) { + cpu_flush_pending = 0; + cr0 ^= 0x80000000; + flushmmucache(); + } + #ifndef USE_NEW_DYNAREC if (!use32) cpu_state.pc &= 0xffff; diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index c8758bf7e..5b11d6cf6 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -182,6 +182,7 @@ int cpu_rom_prefetch_cycles; int cpu_waitstates; int cpu_cache_int_enabled; int cpu_cache_ext_enabled; +int cpu_flush_pending; int cpu_isa_speed; int cpu_pci_speed; int cpu_isa_pci_div; @@ -1537,6 +1538,52 @@ cpu_set(void) #ifdef USE_AMD_K5 case CPU_K5: case CPU_5K86: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_pentiummmx_0f, dynarec_ops_386, dynarec_ops_pentiummmx_0f); +#else + x86_setopcodes(ops_386, ops_pentiummmx_0f); +#endif /* USE_DYNAREC */ + + timing_rr = 1; /* register dest - register src */ + timing_rm = 2; /* register dest - memory src */ + timing_mr = 3; /* memory dest - register src */ + timing_mm = 3; + timing_rml = 2; /* register dest - memory src long */ + timing_mrl = 3; /* memory dest - register src long */ + timing_mml = 3; + timing_bt = 0; /* branch taken */ + timing_bnt = 1; /* branch not taken */ + + timing_int = 6; + timing_int_rm = 11; + timing_int_v86 = 54; + timing_int_pm = 25; + timing_int_pm_outer = 42; + timing_iret_rm = 7; + timing_iret_v86 = 27; /* unknown */ + timing_iret_pm = 10; + timing_iret_pm_outer = 27; + timing_call_rm = 4; + timing_call_pm = 4; + timing_call_pm_gate = 22; + timing_call_pm_gate_inner = 44; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 3; + timing_jmp_pm = 3; + timing_jmp_pm_gate = 18; + + timing_misaligned = 3; + + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_MMX; + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PGE; + +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_k5); +#endif /* USE_DYNAREC */ + break; + #endif /* USE_AMD_K5 */ case CPU_K6: case CPU_K6_2: @@ -1547,27 +1594,13 @@ cpu_set(void) #ifdef USE_DYNAREC if (cpu_s->cpu_type >= CPU_K6_2) x86_setopcodes(ops_386, ops_k62_0f, dynarec_ops_386, dynarec_ops_k62_0f); -# ifdef USE_AMD_K5 - else if (cpu_s->cpu_type == CPU_K6) - x86_setopcodes(ops_386, ops_k6_0f, dynarec_ops_386, dynarec_ops_k6_0f); - else - x86_setopcodes(ops_386, ops_pentiummmx_0f, dynarec_ops_386, dynarec_ops_pentiummmx_0f); -# else else x86_setopcodes(ops_386, ops_k6_0f, dynarec_ops_386, dynarec_ops_k6_0f); -# endif /* USE_AMD_K5 */ #else if (cpu_s->cpu_type >= CPU_K6_2) x86_setopcodes(ops_386, ops_k62_0f); -# ifdef USE_AMD_K5 - else if (cpu_s->cpu_type == CPU_K6) - x86_setopcodes(ops_386, ops_k6_0f); - else - x86_setopcodes(ops_386, ops_pentiummmx_0f); -# else else x86_setopcodes(ops_386, ops_k6_0f); -# endif /* USE_AMD_K5 */ #endif /* USE_DYNAREC */ if ((cpu_s->cpu_type == CPU_K6_2P) || (cpu_s->cpu_type == CPU_K6_3P)) { @@ -1614,23 +1647,11 @@ cpu_set(void) cpu_features |= CPU_FEATURE_3DNOW; if ((cpu_s->cpu_type == CPU_K6_2P) || (cpu_s->cpu_type == CPU_K6_3P)) cpu_features |= CPU_FEATURE_3DNOWE; -#ifdef USE_AMD_K5 - cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE; - if (cpu_s->cpu_type >= CPU_K6) { - cpu_CR4_mask |= (CR4_VME | CR4_PVI | CR4_PSE); - if (cpu_s->cpu_type <= CPU_K6) - cpu_CR4_mask |= CR4_PCE; - else if (cpu_s->cpu_type >= CPU_K6_2C) - cpu_CR4_mask |= CR4_PGE; - } else - cpu_CR4_mask |= CR4_PGE; -#else cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE; if (cpu_s->cpu_type == CPU_K6) cpu_CR4_mask |= CR4_PCE; else if (cpu_s->cpu_type >= CPU_K6_2C) cpu_CR4_mask |= CR4_PGE; -#endif /* USE_AMD_K5 */ #ifdef USE_DYNAREC codegen_timing_set(&codegen_timing_k6); diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index f5f05b805..bac3450d1 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -617,6 +617,7 @@ extern int cpu_prefetch_width; extern int cpu_mem_prefetch_cycles; extern int cpu_rom_prefetch_cycles; extern int cpu_waitstates; +extern int cpu_flush_pending; extern int cpu_cache_int_enabled; extern int cpu_cache_ext_enabled; extern int cpu_isa_speed; diff --git a/src/cpu/x86.c b/src/cpu/x86.c index 4bf381ee4..d70f8f61c 100644 --- a/src/cpu/x86.c +++ b/src/cpu/x86.c @@ -277,7 +277,7 @@ reset_common(int hard) cr0 = 0; if (is386 && !is486 && (fpu_type == FPU_387)) cr0 |= 0x10; - cpu_cache_int_enabled = 0; + cpu_cache_int_enabled = 0; cpu_update_waitstates(); cr4 = 0; cpu_state.eflags = 0; @@ -325,6 +325,7 @@ reset_common(int hard) if (hard) codegen_reset(); #endif + cpu_flush_pending = 0; if (!hard) flushmmucache(); x86_was_reset = 1; diff --git a/src/cpu/x86_ops_mov_ctrl.h b/src/cpu/x86_ops_mov_ctrl.h index bcfed831b..c8ac9ab63 100644 --- a/src/cpu/x86_ops_mov_ctrl.h +++ b/src/cpu/x86_ops_mov_ctrl.h @@ -9,6 +9,8 @@ opMOV_r_CRx_a16(uint32_t fetchdat) switch (cpu_reg) { case 0: cpu_state.regs[cpu_rm].l = cr0; + if (cpu_flush_pending) + cpu_state.regs[cpu_rm].l ^= 0x80000000; if (is486 || isibm486) cpu_state.regs[cpu_rm].l |= 0x10; /*ET hardwired on 486*/ else { @@ -49,6 +51,8 @@ opMOV_r_CRx_a32(uint32_t fetchdat) switch (cpu_reg) { case 0: cpu_state.regs[cpu_rm].l = cr0; + if (cpu_flush_pending) + cpu_state.regs[cpu_rm].l ^= 0x80000000; if (is486 || isibm486) cpu_state.regs[cpu_rm].l |= 0x10; /*ET hardwired on 486*/ else { @@ -180,12 +184,21 @@ opMOV_CRx_r_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); switch (cpu_reg) { case 0: - if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000001) + if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x00000001) flushmmucache(); + else if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000000) { + if (is_p6 || cpu_use_dynarec) + flushmmucache(); + else + cpu_flush_pending = 1; + } /* Make sure CPL = 0 when switching from real mode to protected mode. */ if ((cpu_state.regs[cpu_rm].l & 0x01) && !(cr0 & 0x01)) cpu_state.seg_cs.access &= 0x9f; - cr0 = cpu_state.regs[cpu_rm].l; + if (!is_p6 && !cpu_use_dynarec && ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000000)) + cr0 = (cr0 & 0x80000000) | (cpu_state.regs[cpu_rm].l & 0x7fffffff); + else + cr0 = cpu_state.regs[cpu_rm].l; if (cpu_16bitbus) cr0 |= 0x10; if (!(cr0 & 0x80000000)) @@ -237,12 +250,21 @@ opMOV_CRx_r_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); switch (cpu_reg) { case 0: - if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000001) + if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x00000001) flushmmucache(); + else if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000000) { + if (is_p6 || cpu_use_dynarec) + flushmmucache(); + else + cpu_flush_pending = 1; + } /* Make sure CPL = 0 when switching from real mode to protected mode. */ if ((cpu_state.regs[cpu_rm].l & 0x01) && !(cr0 & 0x01)) cpu_state.seg_cs.access &= 0x9f; - cr0 = cpu_state.regs[cpu_rm].l; + if (!is_p6 && !cpu_use_dynarec && ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000000)) + cr0 = (cr0 & 0x80000000) | (cpu_state.regs[cpu_rm].l & 0x7fffffff); + else + cr0 = cpu_state.regs[cpu_rm].l; if (cpu_16bitbus) cr0 |= 0x10; if (!(cr0 & 0x80000000)) diff --git a/src/cpu/x86_ops_mov_ctrl_2386.h b/src/cpu/x86_ops_mov_ctrl_2386.h index cae6c9957..6b6db8c94 100644 --- a/src/cpu/x86_ops_mov_ctrl_2386.h +++ b/src/cpu/x86_ops_mov_ctrl_2386.h @@ -9,6 +9,8 @@ opMOV_r_CRx_a16(uint32_t fetchdat) switch (cpu_reg) { case 0: cpu_state.regs[cpu_rm].l = cr0; + if (cpu_flush_pending) + cpu_state.regs[cpu_rm].l ^= 0x80000000; if (is486 || isibm486) cpu_state.regs[cpu_rm].l |= 0x10; /*ET hardwired on 486*/ else { @@ -49,6 +51,8 @@ opMOV_r_CRx_a32(uint32_t fetchdat) switch (cpu_reg) { case 0: cpu_state.regs[cpu_rm].l = cr0; + if (cpu_flush_pending) + cpu_state.regs[cpu_rm].l ^= 0x80000000; if (is486 || isibm486) cpu_state.regs[cpu_rm].l |= 0x10; /*ET hardwired on 486*/ else { @@ -176,12 +180,17 @@ opMOV_CRx_r_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); switch (cpu_reg) { case 0: - if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000001) + if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x00000001) flushmmucache(); + else if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000000) + cpu_flush_pending = 1; /* Make sure CPL = 0 when switching from real mode to protected mode. */ if ((cpu_state.regs[cpu_rm].l & 0x01) && !(cr0 & 0x01)) cpu_state.seg_cs.access &= 0x9f; - cr0 = cpu_state.regs[cpu_rm].l; + if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000000) + cr0 = (cr0 & 0x80000000) | (cpu_state.regs[cpu_rm].l & 0x7fffffff); + else + cr0 = cpu_state.regs[cpu_rm].l; if (cpu_16bitbus) cr0 |= 0x10; if (!(cr0 & 0x80000000)) @@ -233,12 +242,17 @@ opMOV_CRx_r_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); switch (cpu_reg) { case 0: - if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000001) + if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x00000001) flushmmucache(); + else if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000000) + cpu_flush_pending = 1; /* Make sure CPL = 0 when switching from real mode to protected mode. */ if ((cpu_state.regs[cpu_rm].l & 0x01) && !(cr0 & 0x01)) cpu_state.seg_cs.access &= 0x9f; - cr0 = cpu_state.regs[cpu_rm].l; + if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000000) + cr0 = (cr0 & 0x80000000) | (cpu_state.regs[cpu_rm].l & 0x7fffffff); + else + cr0 = cpu_state.regs[cpu_rm].l; if (cpu_16bitbus) cr0 |= 0x10; if (!(cr0 & 0x80000000)) diff --git a/src/cpu/x86_ops_pmode.h b/src/cpu/x86_ops_pmode.h index 4f32b0e37..b68aaffbd 100644 --- a/src/cpu/x86_ops_pmode.h +++ b/src/cpu/x86_ops_pmode.h @@ -431,12 +431,21 @@ op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); if (is386 && is32 && (cpu_mod == 3)) { - if (is486 || isibm486) - seteaw(cr0); - else if (is386 && !cpu_16bitbus) - seteaw(cr0 | /* 0x7FFFFF00 */ 0x7FFFFFE0); - else - seteaw(cr0 | 0x7FFFFFF0); + if (cpu_flush_pending) { + if (is486 || isibm486) + seteaw(cr0 ^ 0x80000000); + else if (is386 && !cpu_16bitbus) + seteaw((cr0 ^ 0x80000000) | /* 0x7FFFFF00 */ 0x7FFFFFE0); + else + seteaw((cr0 ^ 0x80000000) | 0x7FFFFFF0); + } else { + if (is486 || isibm486) + seteaw(cr0); + else if (is386 && !cpu_16bitbus) + seteaw(cr0 | /* 0x7FFFFF00 */ 0x7FFFFFE0); + else + seteaw(cr0 | 0x7FFFFFF0); + } } else { if (is486 || isibm486) seteaw(msw); diff --git a/src/device/cartridge.c b/src/device/cartridge.c index a40c29c9b..52f36a4ca 100644 --- a/src/device/cartridge.c +++ b/src/device/cartridge.c @@ -35,6 +35,7 @@ typedef struct cart_t { } cart_t; char cart_fns[2][512]; +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 1d0b88531..a239c6393 100644 --- a/src/device/cassette.c +++ b/src/device/cassette.c @@ -45,6 +45,7 @@ pc_cassette_t *cassette; char cassette_fname[512]; char cassette_mode[512]; +char * cassette_image_history[CASSETTE_IMAGE_HISTORY]; unsigned long cassette_pos; unsigned long cassette_srate; int cassette_enable; diff --git a/src/include/86box/cartridge.h b/src/include/86box/cartridge.h index 2fa0a9358..2ea7ec734 100644 --- a/src/include/86box/cartridge.h +++ b/src/include/86box/cartridge.h @@ -21,7 +21,10 @@ extern "C" { #endif +#define CART_IMAGE_HISTORY 4 + extern char cart_fns[2][512]; +extern char *cart_image_history[2][CART_IMAGE_HISTORY]; extern void cart_load(int drive, char *fn); extern void cart_close(int drive); diff --git a/src/include/86box/cassette.h b/src/include/86box/cassette.h index 3706ca632..bb0899e24 100644 --- a/src/include/86box/cassette.h +++ b/src/include/86box/cassette.h @@ -153,10 +153,13 @@ void pc_cas_print_state(const pc_cassette_t *cas); void pc_cas_clock(pc_cassette_t *cas, unsigned long cnt); void pc_cas_advance(pc_cassette_t *cas); +#define CASSETTE_IMAGE_HISTORY 4 + extern pc_cassette_t *cassette; extern char cassette_fname[512]; extern char cassette_mode[512]; +extern char * cassette_image_history[CASSETTE_IMAGE_HISTORY]; extern unsigned long cassette_pos; extern unsigned long cassette_srate; extern int cassette_enable; diff --git a/src/include/86box/video.h b/src/include/86box/video.h index aee8c4b4d..dfbf072c5 100644 --- a/src/include/86box/video.h +++ b/src/include/86box/video.h @@ -529,6 +529,7 @@ extern const device_t s3_trio64v2_dx_onboard_pci_device; extern const device_t s3_virge_325_pci_device; extern const device_t s3_virge_325_onboard_pci_device; extern const device_t s3_diamond_stealth_2000_pci_device; +extern const device_t s3_mirocrystal_3d_pci_device; extern const device_t s3_diamond_stealth_3000_pci_device; extern const device_t s3_stb_velocity_3d_pci_device; extern const device_t s3_virge_375_pci_device; diff --git a/src/machine/m_pcjr.c b/src/machine/m_pcjr.c index 789481047..16020826d 100644 --- a/src/machine/m_pcjr.c +++ b/src/machine/m_pcjr.c @@ -1438,6 +1438,34 @@ speed_changed(void *priv) recalc_timings(pcjr); } +static void +pcjr_vid_init(pcjr_t *pcjr) +{ + int display_type; + + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_dram); + + pcjr->memctrl = -1; + if (mem_size < 128) + pcjr->memctrl &= ~0x24; + + display_type = device_get_config_int("display_type"); + pcjr->composite = (display_type != PCJR_RGB); + pcjr->apply_hd = device_get_config_int("apply_hd"); + overscan_x = 256; + overscan_y = 32; + + mem_mapping_add(&pcjr->mapping, 0xb8000, 0x08000, + vid_read, NULL, NULL, + vid_write, NULL, NULL, NULL, 0, pcjr); + io_sethandler(0x03d0, 16, + vid_in, NULL, NULL, vid_out, NULL, NULL, pcjr); + timer_add(&pcjr->timer, vid_poll, pcjr, 1); + + cga_palette = 0; + cgapal_rebuild(); +} + void pit_irq0_timer_pcjr(int new_out, int old_out, UNUSED(void *priv)) { @@ -1494,7 +1522,6 @@ const device_t pcjr_device = { int machine_pcjr_init(UNUSED(const machine_t *model)) { - int display_type; pcjr_t *pcjr; int ret; @@ -1507,14 +1534,6 @@ machine_pcjr_init(UNUSED(const machine_t *model)) pcjr = malloc(sizeof(pcjr_t)); memset(pcjr, 0x00, sizeof(pcjr_t)); - pcjr->memctrl = -1; - if (mem_size < 128) - pcjr->memctrl &= ~0x24; - display_type = machine_get_config_int("display_type"); - pcjr->composite = (display_type != PCJR_RGB); - pcjr->apply_hd = machine_get_config_int("apply_hd"); - overscan_x = 256; - overscan_y = 32; pic_init_pcjr(); pit_common_init(0, pit_irq0_timer_pcjr, NULL); @@ -1524,16 +1543,10 @@ machine_pcjr_init(UNUSED(const machine_t *model)) /* Initialize the video controller. */ video_reset(gfxcard[0]); loadfont("roms/video/mda/mda.rom", 0); - mem_mapping_add(&pcjr->mapping, 0xb8000, 0x08000, - vid_read, NULL, NULL, - vid_write, NULL, NULL, NULL, 0, pcjr); - io_sethandler(0x03d0, 16, - vid_in, NULL, NULL, vid_out, NULL, NULL, pcjr); - timer_add(&pcjr->timer, vid_poll, pcjr, 1); - video_inform(VIDEO_FLAG_TYPE_CGA, &timing_dram); + device_context(&pcjr_device); + pcjr_vid_init(pcjr); + device_context_restore(); device_add_ex(&pcjr_device, pcjr); - cga_palette = 0; - cgapal_rebuild(); /* Initialize the keyboard. */ keyboard_scan = 1; diff --git a/src/machine/m_tandy.c b/src/machine/m_tandy.c index 2a7ef2275..6c478b37a 100644 --- a/src/machine/m_tandy.c +++ b/src/machine/m_tandy.c @@ -1328,11 +1328,10 @@ vid_init(tandy_t *dev) vid = malloc(sizeof(t1kvid_t)); memset(vid, 0x00, sizeof(t1kvid_t)); vid->memctrl = -1; - dev->vid = vid; video_inform(VIDEO_FLAG_TYPE_CGA, &timing_dram); - display_type = machine_get_config_int("display_type"); + display_type = device_get_config_int("display_type"); vid->composite = (display_type != TANDY_RGB); cga_comp_init(1); @@ -1345,11 +1344,14 @@ vid_init(tandy_t *dev) io_sethandler(0x0065, 1, vid_in, NULL, NULL, vid_out, NULL, NULL, dev); } else vid->b8000_mask = 0x3fff; + timer_add(&vid->timer, vid_poll, dev, 1); mem_mapping_add(&vid->mapping, 0xb8000, 0x08000, vid_read, NULL, NULL, vid_write, NULL, NULL, NULL, 0, dev); io_sethandler(0x03d0, 16, vid_in, NULL, NULL, vid_out, NULL, NULL, dev); + + dev->vid = vid; } const device_config_t vid_config[] = { @@ -1771,7 +1773,9 @@ machine_tandy1k_init(const machine_t *model, int type) keyboard_set_table(scancode_tandy); io_sethandler(0x00a0, 1, tandy_read, NULL, NULL, tandy_write, NULL, NULL, dev); + device_context(&vid_device); vid_init(dev); + device_context_restore(); device_add_ex(&vid_device, dev); device_add((type == TYPE_TANDY1000SX) ? &ncr8496_device : &sn76489_device); break; @@ -1781,8 +1785,10 @@ machine_tandy1k_init(const machine_t *model, int type) keyboard_set_table(scancode_tandy); io_sethandler(0x00a0, 1, tandy_read, NULL, NULL, tandy_write, NULL, NULL, dev); + device_context(&vid_device_hx); vid_init(dev); - device_add_ex(&vid_device, dev); + device_context_restore(); + device_add_ex(&vid_device_hx, dev); device_add(&ncr8496_device); device_add(&eep_1000hx_device); break; @@ -1792,7 +1798,9 @@ machine_tandy1k_init(const machine_t *model, int type) init_rom(dev); io_sethandler(0xffe8, 8, tandy_read, NULL, NULL, tandy_write, NULL, NULL, dev); + device_context(&vid_device_sl); vid_init(dev); + device_context_restore(); device_add_ex(&vid_device_sl, dev); device_add(&pssj_device); device_add(&eep_1000sl2_device); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index b482951ef..c0c0e9085 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -14678,7 +14678,7 @@ const machine_t machines[] = { /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC firmware. */ { - .name = "[SMSC VictoryBX-66] A-Trend ATC-6310BXII", + .name = "[SMSC VictoryBX-66] A-Trend ATC6310BXII", .internal_name = "atc6310bxii", .type = MACHINE_TYPE_SLOT1, .chipset = MACHINE_CHIPSET_SMSC_VICTORYBX_66, @@ -15397,7 +15397,7 @@ const machine_t machines[] = { /* Has a Winbond W83977EF Super I/O chip with on-chip KBC with AMIKey-2 KBC firmware. */ { - .name = "[SMSC VictoryBX-66] A-Trend ATC-7020BXII", + .name = "[SMSC VictoryBX-66] A-Trend ATC7020BXII", .internal_name = "atc7020bxii", .type = MACHINE_TYPE_SOCKET370, .chipset = MACHINE_CHIPSET_SMSC_VICTORYBX_66, diff --git a/src/network/net_tulip.c b/src/network/net_tulip.c index 060e11fba..ca43b0844 100644 --- a/src/network/net_tulip.c +++ b/src/network/net_tulip.c @@ -1638,7 +1638,7 @@ nic_init(const device_t *info) s->pci_conf[0x04] = 7; /* Enable our BIOS space in PCI, if needed. */ - if (s->bios_addr > 0) { + 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; } else diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index b3e01c1b9..cf9420a4d 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -227,6 +227,10 @@ if(WIN32 AND NOT MINGW) target_sources(plat PRIVATE win_opendir.c) endif() +if(WIN32 AND NOT CPPTHREADS) + target_sources(plat PRIVATE win_thread.c) +endif() + if(WIN32) target_sources(plat PRIVATE win_serial_passthrough.c win_netsocket.c) else() diff --git a/src/qt/qt_mediahistorymanager.cpp b/src/qt/qt_mediahistorymanager.cpp index 672ccfa8d..9886c205b 100644 --- a/src/qt/qt_mediahistorymanager.cpp +++ b/src/qt/qt_mediahistorymanager.cpp @@ -24,8 +24,15 @@ extern "C" { #include <86box/timer.h> -#include <86box/cdrom.h> +#include <86box/device.h> +#include <86box/cassette.h> +#include <86box/cartridge.h> #include <86box/fdd.h> +#include <86box/cdrom.h> +#include <86box/scsi_device.h> +#include <86box/zip.h> +#include <86box/mo.h> +#include <86box/path.h> } namespace ui { @@ -100,7 +107,14 @@ MediaHistoryManager::getImageForSlot(int index, int slot, ui::MediaType type) int MediaHistoryManager::maxDevicesSupported(ui::MediaType type) { - return type == ui::MediaType::Cassette ? 1 : 4; + switch (type) { + default: + return 4; + case ui::MediaType::Cassette: + return 1; + case ui::MediaType::Cartridge: + return 2; + } } void @@ -163,14 +177,26 @@ MediaHistoryManager::initialDeduplication() for (int device_index = 0; device_index < maxDevicesSupported(device_type); device_index++) { device_index_list_t device_history = getHistoryListForDeviceIndex(device_index, device_type); switch (device_type) { - case ui::MediaType::Optical: - current_image = cdrom[device_index].image_path; + default: + continue; + break; + case ui::MediaType::Cassette: + current_image = cassette_fname; + break; + case ui::MediaType::Cartridge: + current_image = cart_fns[device_index]; break; case ui::MediaType::Floppy: current_image = floppyfns[device_index]; break; - default: - continue; + case ui::MediaType::Optical: + current_image = cdrom[device_index].image_path; + break; + case ui::MediaType::Zip: + current_image = zip_drives[device_index].image_path; + break; + case ui::MediaType::Mo: + current_image = mo_drives[device_index].image_path; break; } deduplicateList(device_history, QVector(1, current_image)); @@ -190,12 +216,20 @@ char ** MediaHistoryManager::getEmuHistoryVarForType(ui::MediaType type, int index) { switch (type) { - case ui::MediaType::Optical: - return &cdrom[index].image_history[0]; - case ui::MediaType::Floppy: - return &fdd_image_history[index][0]; default: return nullptr; + case ui::MediaType::Cassette: + return &cassette_image_history[0]; + case ui::MediaType::Cartridge: + return &cart_image_history[index][0]; + case ui::MediaType::Floppy: + return &fdd_image_history[index][0]; + case ui::MediaType::Optical: + return &cdrom[index].image_history[0]; + case ui::MediaType::Zip: + return &zip_drives[index].image_history[0]; + case ui::MediaType::Mo: + return &mo_drives[index].image_history[0]; } } @@ -275,9 +309,6 @@ MediaHistoryManager::pathAdjustSingle(QString checked_path) if (file_info.filePath().isEmpty() || current_usr_path.isEmpty() || file_info.isRelative()) { return checked_path; } - if (file_info.filePath().startsWith(current_usr_path)) { - checked_path = file_info.filePath().remove(current_usr_path); - } return checked_path; } @@ -304,10 +335,25 @@ MediaHistoryManager::removeMissingImages(device_index_list_t &device_history) if (file_info.filePath().isEmpty()) { continue; } - // For this check, explicitly prepend `usr_path` to relative paths to account for $CWD platform variances - QFileInfo absolute_path = file_info.isRelative() ? QFileInfo(getUsrPath().append(file_info.filePath())) : file_info; - if ((file_info.filePath().left(8) != "ioctl://") && !absolute_path.exists()) { - qWarning("Image file %s does not exist - removing from history", qPrintable(file_info.filePath())); + + char *p = checked_path.toUtf8().data(); + char temp[1024] = { 0 }; + + if (path_abs(p)) { + if (strlen(p) > (MAX_IMAGE_PATH_LEN - 1)) + fatal("removeMissingImages(): strlen(p) > 2047\n"); + else + snprintf(temp, (MAX_IMAGE_PATH_LEN - 1), "%s", p); + } else + snprintf(temp, (MAX_IMAGE_PATH_LEN - 1), "%s%s%s", usr_path, + path_get_slash(usr_path), p); + path_normalize(temp); + + QString qstr = QString::fromUtf8(temp); + QFileInfo new_fi(qstr); + + if ((new_fi.filePath().left(8) != "ioctl://") && !new_fi.exists()) { + qWarning("Image file %s does not exist - removing from history", qPrintable(new_fi.filePath())); checked_path = ""; } } diff --git a/src/qt/qt_mediahistorymanager.hpp b/src/qt/qt_mediahistorymanager.hpp index 4eae46f9c..29ada8e2a 100644 --- a/src/qt/qt_mediahistorymanager.hpp +++ b/src/qt/qt_mediahistorymanager.hpp @@ -47,7 +47,8 @@ enum class MediaType { Optical, Zip, Mo, - Cassette + Cassette, + Cartridge }; // This macro allows us to do a reverse lookup of the enum with `QMetaEnum` Q_ENUM_NS(MediaType) @@ -61,6 +62,10 @@ typedef QHash master_list_t; static const MediaType AllSupportedMediaHistoryTypes[] = { MediaType::Optical, MediaType::Floppy, + MediaType::Zip, + MediaType::Mo, + MediaType::Cassette, + MediaType::Cartridge }; class MediaHistoryManager { diff --git a/src/qt/qt_mediamenu.cpp b/src/qt/qt_mediamenu.cpp index c80d9d17f..d9db79db0 100644 --- a/src/qt/qt_mediamenu.cpp +++ b/src/qt/qt_mediamenu.cpp @@ -91,6 +91,11 @@ MediaMenu::refresh(QMenu *parentMenu) cassetteMenu->addAction(tr("&Existing image..."), [this]() { cassetteSelectImage(false); }); cassetteMenu->addAction(tr("Existing image (&Write-protected)..."), [this]() { cassetteSelectImage(true); }); cassetteMenu->addSeparator(); + for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) { + cassetteImageHistoryPos[slot] = cassetteMenu->children().count(); + cassetteMenu->addAction(QString::asprintf(tr("Image %i").toUtf8().constData(), slot), [this, slot]() { cassetteMenuSelect(slot); })->setCheckable(false); + } + cassetteMenu->addSeparator(); cassetteRecordPos = cassetteMenu->children().count(); cassetteMenu->addAction(tr("&Record"), [this] { pc_cas_set_mode(cassette, 1); cassetteUpdateMenu(); })->setCheckable(true); cassettePlayPos = cassetteMenu->children().count(); @@ -111,6 +116,11 @@ MediaMenu::refresh(QMenu *parentMenu) auto *menu = parentMenu->addMenu(""); menu->addAction(tr("&Image..."), [this, i]() { cartridgeSelectImage(i); }); menu->addSeparator(); + for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) { + cartridgeImageHistoryPos[slot] = menu->children().count(); + menu->addAction(QString::asprintf(tr("Image %i").toUtf8().constData(), slot), [this, i, slot]() { cartridgeMenuSelect(i, slot); })->setCheckable(false); + } + menu->addSeparator(); cartridgeEjectPos = menu->children().count(); menu->addAction(tr("E&ject"), [this, i]() { cartridgeEject(i); }); cartridgeMenus[i] = menu; @@ -179,10 +189,13 @@ MediaMenu::refresh(QMenu *parentMenu) menu->addAction(tr("&Existing image..."), [this, i]() { zipSelectImage(i, false); }); menu->addAction(tr("Existing image (&Write-protected)..."), [this, i]() { zipSelectImage(i, true); }); menu->addSeparator(); + for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) { + zipImageHistoryPos[slot] = menu->children().count(); + menu->addAction(QString::asprintf(tr("Image %i").toUtf8().constData(), slot), [this, i, slot]() { zipReload(i, slot); })->setCheckable(false); + } + menu->addSeparator(); zipEjectPos = menu->children().count(); menu->addAction(tr("E&ject"), [this, i]() { zipEject(i); }); - zipReloadPos = menu->children().count(); - menu->addAction(tr("&Reload previous image"), [this, i]() { zipReload(i); }); zipMenus[i] = menu; zipUpdateMenu(i); }); @@ -195,10 +208,13 @@ MediaMenu::refresh(QMenu *parentMenu) menu->addAction(tr("&Existing image..."), [this, i]() { moSelectImage(i, false); }); menu->addAction(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(); + menu->addAction(QString::asprintf(tr("Image %i").toUtf8().constData(), slot), [this, i, slot]() { moReload(i, slot); })->setCheckable(false); + } + menu->addSeparator(); moEjectPos = menu->children().count(); menu->addAction(tr("E&ject"), [this, i]() { moEject(i); }); - moReloadPos = menu->children().count(); - menu->addAction(tr("&Reload previous image"), [this, i]() { moReload(i); }); moMenus[i] = menu; moUpdateMenu(i); }); @@ -243,9 +259,19 @@ MediaMenu::cassetteSelectImage(bool wp) cassetteMount(filename, wp); } +void +MediaMenu::cassetteMenuSelect(int slot) +{ + QString filename = mhm.getImageForSlot(0, slot, ui::MediaType::Cassette); + cassetteMount(filename.toUtf8().constData(), 0); + cassetteUpdateMenu(); + ui_sb_update_tip(SB_CASSETTE); +} + void MediaMenu::cassetteMount(const QString &filename, bool wp) { + auto previous_image = QFileInfo(cassette_fname); pc_cas_set_fname(cassette, nullptr); memset(cassette_fname, 0, sizeof(cassette_fname)); cassette_ui_writeprot = wp ? 1 : 0; @@ -257,6 +283,7 @@ MediaMenu::cassetteMount(const QString &filename, bool wp) } ui_sb_update_icon_state(SB_CASSETTE, filename.isEmpty() ? 1 : 0); + mhm.addImageToHistory(0, ui::MediaType::Cassette, previous_image.filePath(), filename); cassetteUpdateMenu(); ui_sb_update_tip(SB_CASSETTE); config_save(); @@ -265,6 +292,7 @@ MediaMenu::cassetteMount(const QString &filename, bool wp) void MediaMenu::cassetteEject() { + mhm.addImageToHistory(0, ui::MediaType::Cassette, cassette_fname, QString()); pc_cas_set_fname(cassette, nullptr); memset(cassette_fname, 0, sizeof(cassette_fname)); ui_sb_update_icon_state(SB_CASSETTE, 1); @@ -297,16 +325,22 @@ MediaMenu::cassetteUpdateMenu() cassetteMenu->setTitle(QString::asprintf(tr("Cassette: %s").toUtf8().constData(), (name.isEmpty() ? tr("(empty)") : name).toUtf8().constData())); + + for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) { + updateImageHistory(0, slot, ui::MediaType::Cassette); + } } void MediaMenu::cartridgeMount(int i, const QString &filename) { + auto previous_image = QFileInfo(cart_fns[i]); cart_close(i); QByteArray filenameBytes = filename.toUtf8(); cart_load(i, filenameBytes.data()); ui_sb_update_icon_state(SB_CARTRIDGE | i, filename.isEmpty() ? 1 : 0); + mhm.addImageToHistory(i, ui::MediaType::Cartridge, previous_image.filePath(), filename); cartridgeUpdateMenu(i); ui_sb_update_tip(SB_CARTRIDGE | i); config_save(); @@ -327,9 +361,19 @@ MediaMenu::cartridgeSelectImage(int i) cartridgeMount(i, filename); } +void +MediaMenu::cartridgeMenuSelect(int index, int slot) +{ + QString filename = mhm.getImageForSlot(index, slot, ui::MediaType::Cartridge); + cartridgeMount(index, filename.toUtf8().constData()); + cartridgeUpdateMenu(index); + ui_sb_update_tip(SB_CARTRIDGE | index); +} + void MediaMenu::cartridgeEject(int i) { + mhm.addImageToHistory(i, ui::MediaType::Cartridge, cart_fns[i], QString()); cart_close(i); ui_sb_update_icon_state(SB_CARTRIDGE | i, 1); cartridgeUpdateMenu(i); @@ -347,6 +391,10 @@ MediaMenu::cartridgeUpdateMenu(int i) ejectMenu->setEnabled(!name.isEmpty()); // menu->setTitle(tr("Cartridge %1: %2").arg(QString::number(i+1), name.isEmpty() ? tr("(empty)") : name)); menu->setTitle(QString::asprintf(tr("Cartridge %i: %ls").toUtf8().constData(), i + 1, name.isEmpty() ? tr("(empty)").toStdU16String().data() : name.toStdU16String().data())); + + for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) { + updateImageHistory(i, slot, ui::MediaType::Cartridge); + } } void @@ -580,6 +628,36 @@ MediaMenu::updateImageHistory(int index, int slot, ui::MediaType type) QString menu_item_name; switch (type) { + default: + menu_item_name = fi.fileName().isEmpty() ? tr("previous image").toUtf8().constData() : fi.fileName().toUtf8().constData(); + return; + case ui::MediaType::Cassette: + if (!MachineStatus::hasCassette()) + return; + menu = cassetteMenu; + children = menu->children(); + imageHistoryUpdatePos = dynamic_cast(children[cassetteImageHistoryPos[slot]]); + fi.setFile(fn); + menu_item_name = fi.fileName().isEmpty() ? tr("previous image").toUtf8().constData() : fi.fileName().toUtf8().constData(); + break; + case ui::MediaType::Cartridge: + if (!machine_has_cartridge(machine)) + return; + menu = cartridgeMenus[index]; + children = menu->children(); + imageHistoryUpdatePos = dynamic_cast(children[cartridgeImageHistoryPos[slot]]); + fi.setFile(fn); + menu_item_name = fi.fileName().isEmpty() ? tr("previous image").toUtf8().constData() : fi.fileName().toUtf8().constData(); + break; + case ui::MediaType::Floppy: + if (!floppyMenus.contains(index)) + return; + menu = floppyMenus[index]; + children = menu->children(); + imageHistoryUpdatePos = dynamic_cast(children[floppyImageHistoryPos[slot]]); + fi.setFile(fn); + menu_item_name = fi.fileName().isEmpty() ? tr("previous image").toUtf8().constData() : fi.fileName().toUtf8().constData(); + break; case ui::MediaType::Optical: if (!cdromMenus.contains(index)) return; @@ -600,18 +678,24 @@ MediaMenu::updateImageHistory(int index, int slot, ui::MediaType type) } imageHistoryUpdatePos->setIcon(menu_icon); break; - case ui::MediaType::Floppy: - if (!floppyMenus.contains(index)) + case ui::MediaType::Zip: + if (!zipMenus.contains(index)) return; - menu = floppyMenus[index]; + menu = zipMenus[index]; children = menu->children(); - imageHistoryUpdatePos = dynamic_cast(children[floppyImageHistoryPos[slot]]); + imageHistoryUpdatePos = dynamic_cast(children[zipImageHistoryPos[slot]]); fi.setFile(fn); menu_item_name = fi.fileName().isEmpty() ? tr("previous image").toUtf8().constData() : fi.fileName().toUtf8().constData(); break; - default: + case ui::MediaType::Mo: + if (!moMenus.contains(index)) + return; + menu = moMenus[index]; + children = menu->children(); + imageHistoryUpdatePos = dynamic_cast(children[moImageHistoryPos[slot]]); + fi.setFile(fn); menu_item_name = fi.fileName().isEmpty() ? tr("previous image").toUtf8().constData() : fi.fileName().toUtf8().constData(); - return; + break; } imageHistoryUpdatePos->setText(QString::asprintf(tr("%s").toUtf8().constData(), menu_item_name.toUtf8().constData())); @@ -727,6 +811,7 @@ MediaMenu::zipMount(int i, const QString &filename, bool wp) zip_load(dev, filenameBytes.data()); zip_insert(dev); } + mhm.addImageToHistory(i, ui::MediaType::Zip, zip_drives[i].prev_image_path, zip_drives[i].image_path); ui_sb_update_icon_state(SB_ZIP | i, filename.isEmpty() ? 1 : 0); zipUpdateMenu(i); @@ -740,6 +825,7 @@ MediaMenu::zipEject(int i) { const auto dev = static_cast(zip_drives[i].priv); + mhm.addImageToHistory(i, ui::MediaType::Zip, zip_drives[i].image_path, QString()); zip_disk_close(dev); zip_drives[i].image_path[0] = 0; if (zip_drives[i].bus_type) { @@ -754,7 +840,7 @@ MediaMenu::zipEject(int i) } void -MediaMenu::zipReload(int i) +MediaMenu::zipReloadPrev(int i) { const auto dev = static_cast(zip_drives[i].priv); @@ -771,6 +857,15 @@ MediaMenu::zipReload(int i) config_save(); } +void +MediaMenu::zipReload(int index, int slot) +{ + const QString filename = mhm.getImageForSlot(index, slot, ui::MediaType::Zip); + zipMount(index, filename, false); + zipUpdateMenu(index); + ui_sb_update_tip(SB_ZIP | index); +} + void MediaMenu::zipUpdateMenu(int i) { @@ -800,6 +895,9 @@ MediaMenu::zipUpdateMenu(int i) // menu->setTitle(tr("ZIP %1 %2 (%3): %4").arg((zip_drives[i].is_250 > 0) ? "250" : "100", QString::number(i+1), busName, name.isEmpty() ? tr("(empty)") : name)); menu->setTitle(QString::asprintf(tr("ZIP %03i %i (%s): %ls").toUtf8().constData(), (zip_drives[i].is_250 > 0) ? 250 : 100, i + 1, busName.toUtf8().data(), name.isEmpty() ? tr("(empty)").toStdU16String().data() : name.toStdU16String().data())); + + for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) + updateImageHistory(i, slot, ui::MediaType::Zip); } void @@ -844,6 +942,7 @@ MediaMenu::moMount(int i, const QString &filename, bool wp) mo_load(dev, filenameBytes.data()); mo_insert(dev); } + 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); moUpdateMenu(i); @@ -857,6 +956,7 @@ MediaMenu::moEject(int i) { const auto dev = static_cast(mo_drives[i].priv); + mhm.addImageToHistory(i, ui::MediaType::Mo, mo_drives[i].image_path, QString()); mo_disk_close(dev); mo_drives[i].image_path[0] = 0; if (mo_drives[i].bus_type) { @@ -871,7 +971,7 @@ MediaMenu::moEject(int i) } void -MediaMenu::moReload(int i) +MediaMenu::moReloadPrev(int i) { mo_t *dev = (mo_t *) mo_drives[i].priv; @@ -888,6 +988,15 @@ MediaMenu::moReload(int i) config_save(); } +void +MediaMenu::moReload(int index, int slot) +{ + const QString filename = mhm.getImageForSlot(index, slot, ui::MediaType::Mo); + moMount(index, filename, false); + moUpdateMenu(index); + ui_sb_update_tip(SB_MO | index); +} + void MediaMenu::moUpdateMenu(int i) { @@ -916,6 +1025,9 @@ MediaMenu::moUpdateMenu(int i) } menu->setTitle(QString::asprintf(tr("MO %i (%ls): %ls").toUtf8().constData(), i + 1, busName.toStdU16String().data(), name.isEmpty() ? tr("(empty)").toStdU16String().data() : name.toStdU16String().data())); + + for (int slot = 0; slot < MAX_PREV_IMAGES; slot++) + updateImageHistory(i, slot, ui::MediaType::Mo); } void @@ -1043,7 +1155,7 @@ zip_mount(uint8_t id, char *fn, uint8_t wp) void zip_reload(uint8_t id) { - MediaMenu::ptr->zipReload(id); + MediaMenu::ptr->zipReloadPrev(id); } void @@ -1061,6 +1173,6 @@ mo_mount(uint8_t id, char *fn, uint8_t wp) void mo_reload(uint8_t id) { - MediaMenu::ptr->moReload(id); + MediaMenu::ptr->moReloadPrev(id); } } diff --git a/src/qt/qt_mediamenu.hpp b/src/qt/qt_mediamenu.hpp index 725ce92b3..aec2f553f 100644 --- a/src/qt/qt_mediamenu.hpp +++ b/src/qt/qt_mediamenu.hpp @@ -24,12 +24,14 @@ public: void cassetteNewImage(); void cassetteSelectImage(bool wp); void cassetteMount(const QString &filename, bool wp); + void cassetteMenuSelect(int slot); void cassetteEject(); void cassetteUpdateMenu(); void cartridgeSelectImage(int i); void cartridgeMount(int i, const QString &filename); void cartridgeEject(int i); + void cartridgeMenuSelect(int index, int slot); void cartridgeUpdateMenu(int i); void floppyNewImage(int i); @@ -53,14 +55,16 @@ public: void zipSelectImage(int i, bool wp); void zipMount(int i, const QString &filename, bool wp); void zipEject(int i); - void zipReload(int i); + void zipReloadPrev(int i); + void zipReload(int index, int slot); void zipUpdateMenu(int i); void moNewImage(int i); void moSelectImage(int i, bool wp); void moMount(int i, const QString &filename, bool wp); void moEject(int i); - void moReload(int i); + void moReloadPrev(int i); + void moReload(int index, int slot); void moUpdateMenu(int i); void nicConnect(int i); @@ -94,24 +98,28 @@ private: int cassetteRewindPos; int cassetteFastFwdPos; int cassetteEjectPos; + int cassetteImageHistoryPos[MAX_PREV_IMAGES]; int cartridgeEjectPos; + int cartridgeImageHistoryPos[MAX_PREV_IMAGES]; int floppyExportPos; int floppyEjectPos; + int floppyImageHistoryPos[MAX_PREV_IMAGES]; int cdromMutePos; int cdromReloadPos; int cdromImagePos; int cdromDirPos; int cdromImageHistoryPos[MAX_PREV_IMAGES]; - int floppyImageHistoryPos[MAX_PREV_IMAGES]; int zipEjectPos; int zipReloadPos; + int zipImageHistoryPos[MAX_PREV_IMAGES]; int moEjectPos; int moReloadPos; + int moImageHistoryPos[MAX_PREV_IMAGES]; int netDisconnPos; diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index 8a9bedf02..3f64d3b3a 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -9219,18 +9219,19 @@ s3_pci_read(UNUSED(int func), int addr, void *priv) return s3->pci_regs[PCI_REG_COMMAND] | 0x80; /*Respond to IO and memory accesses*/ else return s3->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ - break; + break; case 0x07: return (s3->chip == S3_TRIO64V2) ? (s3->pci_regs[0x07] & 0x36) : (1 << 1); /*Medium DEVSEL timing*/ - case 0x08: switch (s3->chip) { /*Revision ID*/ - case S3_TRIO64V: - return 0x40; - case S3_TRIO64V2: - return 0x16; /*Confirmed on an onboard 64V2/DX*/ - default: - return 0x00; + case 0x08: + switch (s3->chip) { /*Revision ID*/ + case S3_TRIO64V: + return 0x40; + case S3_TRIO64V2: + return 0x16; /*Confirmed on an onboard 64V2/DX*/ + default: + return 0x00; } break; case 0x09: @@ -9252,24 +9253,13 @@ s3_pci_read(UNUSED(int func), int addr, void *priv) case 0x0d: return (s3->chip == S3_TRIO64V2) ? (s3->pci_regs[0x0d] & 0xf8) : 0x00; - case 0x10: - return 0x00; /*Linear frame buffer address*/ - case 0x11: - return 0x00; case 0x12: - if (svga->crtc[0x53] & 0x08) - return 0x00; - else - return (svga->crtc[0x5a] & 0x80); - break; + return ((s3->chip == S3_VISION868) || (s3->chip == S3_VISION968) || (s3->chip >= S3_TRIO64V)) ? 0x00 : + (svga->crtc[0x5a] & 0x80); case 0x13: - if (svga->crtc[0x53] & 0x08) { - return (s3->chip >= S3_TRIO64V) ? (svga->crtc[0x59] & 0xfc) : (svga->crtc[0x59] & 0xfe); - } else { - return svga->crtc[0x59]; - } - break; + return ((s3->chip == S3_VISION868) || (s3->chip == S3_VISION968) || (s3->chip >= S3_TRIO64V)) ? + (svga->crtc[0x59] & 0xfc) : svga->crtc[0x59]; case 0x30: return s3->has_bios ? (s3->pci_regs[0x30] & 0x01) : 0x00; /*BIOS ROM address*/ @@ -9323,13 +9313,16 @@ s3_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv) s3_io_set(s3); else s3_io_remove(s3); - s3->pci_regs[PCI_REG_COMMAND] = (val & 0x23); + if (s3->chip >= S3_TRIO64V) + s3->pci_regs[PCI_REG_COMMAND] = (val & 0x27); + else + s3->pci_regs[PCI_REG_COMMAND] = (val & 0x23); s3_updatemapping(s3); break; case 0x07: if (s3->chip == S3_TRIO64V2) { - s3->pci_regs[0x07] = val & 0x3e; + s3->pci_regs[0x07] &= ~(val & 0x30); return; } break; @@ -9342,18 +9335,14 @@ s3_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv) break; case 0x12: - if (!(svga->crtc[0x53] & 0x08)) { - svga->crtc[0x5a] = (svga->crtc[0x5a] & 0x7f) | (val & 0x80); + if (s3->chip < S3_TRIO64V) { + svga->crtc[0x5a] = val & 0x80; s3_updatemapping(s3); } break; case 0x13: - if (svga->crtc[0x53] & 0x08) { - svga->crtc[0x59] = (s3->chip >= S3_TRIO64V) ? (val & 0xfc) : (val & 0xfe); - } else { - svga->crtc[0x59] = val; - } + svga->crtc[0x59] = (s3->chip >= S3_TRIO64V) ? (val & 0xfc) : val; s3_updatemapping(s3); break; diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index 4bcbaea9e..3719d2591 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -61,6 +61,7 @@ static int dither[4][4] = { #define ROM_VIRGE_325 "roms/video/s3virge/86c325.bin" #define ROM_DIAMOND_STEALTH3D_2000 "roms/video/s3virge/s3virge.bin" +#define ROM_MIROCRYSTAL_3D "roms/video/s3virge/miro Crystal 3D 1.02.bin" #define ROM_DIAMOND_STEALTH3D_3000 "roms/video/s3virge/diamondstealth3000.vbi" #define ROM_STB_VELOCITY_3D "roms/video/s3virge/stb_velocity3d_110.BIN" #define ROM_VIRGE_DX "roms/video/s3virge/86c375_1.bin" @@ -91,6 +92,7 @@ static int dither[4][4] = { enum { S3_VIRGE_325, S3_DIAMOND_STEALTH3D_2000, + S3_MIROCRYSTAL_3D, S3_DIAMOND_STEALTH3D_3000, S3_STB_VELOCITY_3D, S3_VIRGE_DX, @@ -865,7 +867,7 @@ s3_virge_recalctimings(svga_t *svga) video_force_resize_set_monitor(1, svga->monitor_index); } - if (((svga->crtc[0x67] & 0xc) != 0xc) || (virge->chip >= S3_VIRGEGX2)) { /*VGA mode*/ + if ((svga->crtc[0x67] & 0xc) != 0xc) { /*VGA mode*/ svga->ma_latch |= (virge->ma_ext << 16); if (svga->crtc[0x51] & 0x30) svga->rowoffset |= (svga->crtc[0x51] & 0x30) << 4; @@ -896,7 +898,7 @@ s3_virge_recalctimings(svga_t *svga) case 24: svga->render = svga_render_24bpp_highres; if ((virge->chip != S3_VIRGEVX) && (virge->chip < S3_VIRGEGX2)) - svga->rowoffset = (svga->rowoffset * 3) / 4; /*Hack*/ + svga->rowoffset = (svga->rowoffset * 3) >> 2; /*Hack*/ break; case 32: svga->render = svga_render_32bpp_highres; @@ -908,37 +910,32 @@ s3_virge_recalctimings(svga_t *svga) svga->vram_display_mask = (!(svga->crtc[0x31] & 0x08) && (svga->crtc[0x32] & 0x40)) ? 0x3ffff : virge->vram_mask; - - svga->overlay.ena = 0; - - if (virge->chip >= S3_VIRGEGX2 && (svga->crtc[0x67] & 0xc) == 0xc) { - /* ViRGE/GX2 and later does not use primary stream registers. */ - svga->overlay.x = virge->streams.sec_x; - svga->overlay.y = virge->streams.sec_y; - svga->overlay.cur_ysize = virge->streams.sec_h; - - if (virge->streams.buffer_ctrl & 2) - svga->overlay.addr = virge->streams.sec_fb1; - else - svga->overlay.addr = virge->streams.sec_fb0; - - svga->overlay.ena = (svga->overlay.x >= 0) && !!(virge->streams.blend_ctrl & 0x20); - svga->overlay.v_acc = virge->streams.dda_vert_accumulator; - svga->rowoffset = virge->streams.pri_stride >> 3; - svga->vram_display_mask = virge->vram_mask; - } } else { /*Streams mode*/ - if (virge->streams.buffer_ctrl & 1) - svga->ma_latch = virge->streams.pri_fb1 >> 2; - else - svga->ma_latch = virge->streams.pri_fb0 >> 2; + if (virge->chip < S3_VIRGEGX2) { + if (virge->streams.buffer_ctrl & 1) + svga->ma_latch = virge->streams.pri_fb1 >> 2; + else + svga->ma_latch = virge->streams.pri_fb0 >> 2; - svga->hdisp = virge->streams.pri_w + 1; - if (virge->streams.pri_h < svga->dispend) - svga->dispend = virge->streams.pri_h; + svga->hdisp = virge->streams.pri_w + 1; + if (virge->streams.pri_h < svga->dispend) + svga->dispend = virge->streams.pri_h; + + svga->overlay.x = virge->streams.sec_x - virge->streams.pri_x; + svga->overlay.y = virge->streams.sec_y - virge->streams.pri_y; + } else { + svga->ma_latch |= (virge->ma_ext << 16); + if (svga->crtc[0x51] & 0x30) + svga->rowoffset |= (svga->crtc[0x51] & 0x30) << 4; + else if (svga->crtc[0x43] & 0x04) + svga->rowoffset |= 0x100; + if (!svga->rowoffset) + svga->rowoffset = 256; + + svga->overlay.x = virge->streams.sec_x; + svga->overlay.y = virge->streams.sec_y; + } - svga->overlay.x = virge->streams.sec_x - virge->streams.pri_x; - svga->overlay.y = virge->streams.sec_y - virge->streams.pri_y; svga->overlay.cur_ysize = virge->streams.sec_h; if (virge->streams.buffer_ctrl & 2) @@ -947,35 +944,60 @@ s3_virge_recalctimings(svga_t *svga) svga->overlay.addr = virge->streams.sec_fb0; svga->overlay.ena = (svga->overlay.x >= 0); + svga->overlay.h_acc = virge->streams.dda_horiz_accumulator; svga->overlay.v_acc = virge->streams.dda_vert_accumulator; - svga->rowoffset = virge->streams.pri_stride >> 3; + if (virge->chip < S3_VIRGEGX2) + svga->rowoffset = virge->streams.pri_stride >> 3; if (virge->chip <= S3_VIRGEDX && svga->overlay.ena) { svga->overlay.ena = (((virge->streams.blend_ctrl >> 24) & 7) == 0b000) || (((virge->streams.blend_ctrl >> 24) & 7) == 0b101); - } else if (virge->chip == S3_VIRGEGX2 && svga->overlay.ena) { + } else if (virge->chip >= S3_VIRGEGX2 && svga->overlay.ena) { /* 0x20 = Secondary Stream enabled */ /* 0x2000 = Primary Stream enabled */ svga->overlay.ena = !!(virge->streams.blend_ctrl & 0x20); } - switch ((virge->streams.pri_ctrl >> 24) & 0x7) { - case 0: /*RGB-8 (CLUT)*/ - svga->render = svga_render_8bpp_highres; - break; - case 3: /*KRGB-16 (1.5.5.5)*/ - svga->render = svga_render_15bpp_highres; - break; - case 5: /*RGB-16 (5.6.5)*/ - svga->render = svga_render_16bpp_highres; - break; - case 6: /*RGB-24 (8.8.8)*/ - svga->render = svga_render_24bpp_highres; - break; - case 7: /*XRGB-32 (X.8.8.8)*/ - svga->render = svga_render_32bpp_highres; - break; + if (virge->chip >= S3_VIRGEGX2) { + switch (svga->bpp) { + case 8: + svga->render = svga_render_8bpp_highres; + break; + case 15: + svga->render = svga_render_15bpp_highres; + break; + case 16: + svga->render = svga_render_16bpp_highres; + break; + case 24: + svga->render = svga_render_24bpp_highres; + break; + case 32: + svga->render = svga_render_32bpp_highres; + break; + + default: + break; + } + } else { + switch ((virge->streams.pri_ctrl >> 24) & 0x7) { + case 0: /*RGB-8 (CLUT)*/ + svga->render = svga_render_8bpp_highres; + break; + case 3: /*KRGB-16 (1.5.5.5)*/ + svga->render = svga_render_15bpp_highres; + break; + case 5: /*RGB-16 (5.6.5)*/ + svga->render = svga_render_16bpp_highres; + break; + case 6: /*RGB-24 (8.8.8)*/ + svga->render = svga_render_24bpp_highres; + break; + case 7: /*XRGB-32 (X.8.8.8)*/ + svga->render = svga_render_32bpp_highres; + break; + } } svga->vram_display_mask = virge->vram_mask; } @@ -988,29 +1010,6 @@ s3_virge_recalctimings(svga_t *svga) svga->render = svga_render_2bpp_s3_highres; } -static void -s3_virge_update_buffer(virge_t *virge) -{ - svga_t *svga = &virge->svga; - - if ((svga->crtc[0x67] & 0xc) != 0xc) - return; - - if (virge->chip < S3_VIRGEGX2) { - if (virge->streams.buffer_ctrl & 1) - svga->ma_latch = virge->streams.pri_fb1 >> 2; - else - svga->ma_latch = virge->streams.pri_fb0 >> 2; - } - - if (virge->streams.buffer_ctrl & 2) - svga->overlay.addr = virge->streams.sec_fb1; - else - svga->overlay.addr = virge->streams.sec_fb0; - - svga->rowoffset = virge->streams.pri_stride >> 3; -} - static void s3_virge_updatemapping(virge_t *virge) { svga_t *svga = &virge->svga; @@ -1842,39 +1841,46 @@ s3_virge_queue(virge_t *virge, uint32_t addr, uint32_t val, uint32_t type) } static void -s3_virge_mmio_write(uint32_t addr, uint8_t val, void *priv) { +s3_virge_mmio_write(uint32_t addr, uint8_t val, void *priv) +{ virge_t *virge = (virge_t *) priv; if ((addr & 0xffff) < 0x8000) s3_virge_queue(virge, addr, val, FIFO_WRITE_BYTE); - else switch (addr & 0xffff) { - case 0x83b0 ... 0x83df: - s3_virge_out(addr & 0x3ff, val, priv); - break; + else { + switch (addr & 0xffff) { + default: + case 0x83b0 ... 0x83df: + s3_virge_out(addr & 0x3ff, val, priv); + break; - case 0xff20: - virge->serialport = val; - i2c_gpio_set(virge->i2c, !!(val & SERIAL_PORT_SCW), !!(val & SERIAL_PORT_SDW)); - break; + case 0xff20: + virge->serialport = val; + i2c_gpio_set(virge->i2c, !!(val & SERIAL_PORT_SCW), !!(val & SERIAL_PORT_SDW)); + break; + } } } static void -s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *priv) { +s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *priv) +{ virge_t *virge = (virge_t *) priv; if ((addr & 0xfffe) < 0x8000) s3_virge_queue(virge, addr, val, FIFO_WRITE_WORD); - else switch (addr & 0xfffe) { - default: - case 0x83d4: - s3_virge_mmio_write(addr, val, priv); - s3_virge_mmio_write(addr + 1, val >> 8, priv); - break; + else { + switch (addr & 0xfffe) { + default: + case 0x83d4: + s3_virge_mmio_write(addr, val, priv); + s3_virge_mmio_write(addr + 1, val >> 8, priv); + break; - case 0xff20: - s3_virge_mmio_write(addr, val, priv); - break; + case 0xff20: + s3_virge_mmio_write(addr, val, priv); + break; + } } } @@ -1900,8 +1906,9 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) { case 0x8190: virge->streams.sec_ctrl = val; virge->streams.dda_horiz_accumulator = val & 0xfff; - if (val & (1 << 11)) - virge->streams.dda_horiz_accumulator |= 0xfffff800; + if (val & 0x1000) + virge->streams.dda_horiz_accumulator |= ~0xfff; + virge->streams.sdif = (val >> 24) & 7; break; case 0x8194: @@ -1910,50 +1917,56 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) { case 0x8198: virge->streams.sec_filter = val; virge->streams.k1_horiz_scale = val & 0x7ff; - if (val & (1 << 10)) - virge->streams.k1_horiz_scale |= 0xfffff800; + if (val & 0x800) + virge->streams.k1_horiz_scale |= ~0x7ff; + virge->streams.k2_horiz_scale = (val >> 16) & 0x7ff; - if ((val >> 16) & (1 << 10)) - virge->streams.k2_horiz_scale |= 0xfffff800; + if ((val >> 16) & 0x800) + virge->streams.k2_horiz_scale |= ~0x7ff; + + svga_recalctimings(svga); + svga->fullchange = changeframecount; break; case 0x81a0: virge->streams.blend_ctrl = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; break; case 0x81c0: virge->streams.pri_fb0 = val & ((virge->memory_size == 8) ? (val & 0x7fffff) : (val & 0x3fffff)); - s3_virge_update_buffer(virge); + svga_recalctimings(svga); svga->fullchange = changeframecount; break; case 0x81c4: virge->streams.pri_fb1 = ((virge->memory_size == 8) ? (val & 0x7fffff) : (val & 0x3fffff)); - s3_virge_update_buffer(virge); + svga_recalctimings(svga); svga->fullchange = changeframecount; break; case 0x81c8: virge->streams.pri_stride = val & 0xfff; - s3_virge_update_buffer(virge); + svga_recalctimings(svga); svga->fullchange = changeframecount; break; case 0x81cc: virge->streams.buffer_ctrl = val; - s3_virge_update_buffer(virge); + svga_recalctimings(svga); svga->fullchange = changeframecount; break; case 0x81d0: virge->streams.sec_fb0 = val; - s3_virge_update_buffer(virge); + svga_recalctimings(svga); svga->fullchange = changeframecount; break; case 0x81d4: virge->streams.sec_fb1 = val; - s3_virge_update_buffer(virge); + svga_recalctimings(svga); svga->fullchange = changeframecount; break; case 0x81d8: virge->streams.sec_stride = val; - s3_virge_update_buffer(virge); + svga_recalctimings(svga); svga->fullchange = changeframecount; break; case 0x81dc: @@ -1961,18 +1974,21 @@ s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *priv) { break; case 0x81e0: virge->streams.k1_vert_scale = val & 0x7ff; - if (val & (1 << 10)) - virge->streams.k1_vert_scale |= 0xfffff800; + if (val & 0x800) + virge->streams.k1_vert_scale |= ~0x7ff; break; case 0x81e4: virge->streams.k2_vert_scale = val & 0x7ff; - if (val & (1 << 10)) - virge->streams.k2_vert_scale |= 0xfffff800; + if (val & 0x800) + virge->streams.k2_vert_scale |= ~0x7ff; break; case 0x81e8: virge->streams.dda_vert_accumulator = val & 0xfff; - if (val & (1 << 11)) - virge->streams.dda_vert_accumulator |= 0xfffff800; + if (val & 0x1000) + virge->streams.dda_vert_accumulator |= ~0xfff; + + svga_recalctimings(svga); + svga->fullchange = changeframecount; break; case 0x81ec: virge->streams.fifo_ctrl = val; @@ -3966,10 +3982,10 @@ static void s3_virge_hwcursor_draw(svga_t *svga, int displine) { } while (0) static void -s3_virge_overlay_draw(svga_t *svga, int displine) { +s3_virge_overlay_draw(svga_t *svga, int displine) +{ virge_t *virge = (virge_t *) svga->priv; - int offset = (virge->streams.sec_x - virge->streams.pri_x) + 1; - int h_acc = virge->streams.dda_horiz_accumulator; + int offset; int r[8]; int g[8]; int b[8]; @@ -3980,11 +3996,19 @@ s3_virge_overlay_draw(svga_t *svga, int displine) { uint32_t *p; uint8_t *src = &svga->vram[svga->overlay_latch.addr]; + if (virge->chip < S3_VIRGEGX2) + offset = (virge->streams.sec_x - virge->streams.pri_x) + 1; + else + offset = virge->streams.sec_x + 1; + p = &((uint32_t *)buffer32->line[displine])[offset + svga->x_add]; - if ((offset + virge->streams.sec_w) > virge->streams.pri_w) - x_size = (virge->streams.pri_w - virge->streams.sec_x) + 1; - else + if (virge->chip < S3_VIRGEGX2) { + if ((offset + virge->streams.sec_w) > virge->streams.pri_w) + x_size = (virge->streams.pri_w - virge->streams.sec_x) + 1; + else + x_size = virge->streams.sec_w + 1; + } else x_size = virge->streams.sec_w + 1; OVERLAY_SAMPLE(); @@ -3992,13 +4016,14 @@ s3_virge_overlay_draw(svga_t *svga, int displine) { for (x = 0; x < x_size; x++) { *p++ = r[x_read] | (g[x_read] << 8) | (b[x_read] << 16); - h_acc += virge->streams.k1_horiz_scale; - if (h_acc >= 0) { + svga->overlay_latch.h_acc += virge->streams.k1_horiz_scale; + if (svga->overlay_latch.h_acc >= 0) { if ((x_read ^ (x_read + 1)) & ~3) OVERLAY_SAMPLE(); + x_read = (x_read + 1) & 7; - h_acc += (virge->streams.k2_horiz_scale - virge->streams.k1_horiz_scale); + svga->overlay_latch.h_acc += (virge->streams.k2_horiz_scale - virge->streams.k1_horiz_scale); } } @@ -4203,7 +4228,7 @@ s3_virge_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv) s3_virge_updatemapping(virge); return; case 0x07: - virge->pci_regs[0x07] = val & 0x3e; + virge->pci_regs[0x07] &= ~(val & 0x30); return; case 0x0d: virge->pci_regs[0x0d] = val & 0xf8; @@ -4326,6 +4351,9 @@ s3_virge_init(const device_t *info) case S3_DIAMOND_STEALTH3D_2000: bios_fn = ROM_DIAMOND_STEALTH3D_2000; break; + case S3_MIROCRYSTAL_3D: + bios_fn = ROM_MIROCRYSTAL_3D; + break; case S3_DIAMOND_STEALTH3D_3000: bios_fn = ROM_DIAMOND_STEALTH3D_3000; break; @@ -4420,6 +4448,7 @@ s3_virge_init(const device_t *info) switch (info->local) { case S3_VIRGE_325: case S3_DIAMOND_STEALTH3D_2000: + case S3_MIROCRYSTAL_3D: virge->fifo_slots_num = 8; virge->svga.decode_mask = (4 << 20) - 1; virge->virge_id_high = 0x56; @@ -4597,6 +4626,12 @@ s3_virge_325_available(void) return rom_present(ROM_VIRGE_325); } +static int +s3_mirocrystal_3d_available(void) +{ + return rom_present(ROM_MIROCRYSTAL_3D); +} + static int s3_virge_988_diamond_available(void) { @@ -4844,6 +4879,20 @@ const device_t s3_diamond_stealth_2000_pci_device = { .config = s3_virge_config }; +const device_t s3_mirocrystal_3d_pci_device = { + .name = "S3 ViRGE (miroCRYSTAL 3D) PCI", + .internal_name = "mirocrystal_3d_pci", + .flags = DEVICE_PCI, + .local = S3_MIROCRYSTAL_3D, + .init = s3_virge_init, + .close = s3_virge_close, + .reset = s3_virge_reset, + { .available = s3_mirocrystal_3d_available }, + .speed_changed = s3_virge_speed_changed, + .force_redraw = s3_virge_force_redraw, + .config = s3_virge_config +}; + const device_t s3_diamond_stealth_3000_pci_device = { .name = "S3 ViRGE/VX (Diamond Stealth 3D 3000) PCI", .internal_name = "stealth3d_3000_pci", diff --git a/src/video/vid_table.c b/src/video/vid_table.c index 13639d05d..c4dee5719 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -174,6 +174,7 @@ video_cards[] = { { &s3_trio64v2_dx_pci_device }, { &s3_virge_325_pci_device }, { &s3_diamond_stealth_2000_pci_device }, + { &s3_mirocrystal_3d_pci_device }, { &s3_diamond_stealth_3000_pci_device }, { &s3_stb_velocity_3d_pci_device }, { &s3_virge_375_pci_device },