diff --git a/README.md b/README.md index ce38632e6..c01a852b5 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ It is also recommended to use a manager application with 86Box for easier handli * [86Box Manager](https://github.com/86Box/86BoxManager) by [Overdoze](https://github.com/daviunic) (Windows only) * [86Box Manager X](https://github.com/RetBox/86BoxManagerX) by [xafero](https://github.com/xafero) (Cross platform Port of 86Box Manager using Avalonia) +* [Avalonia 86](https://github.com/notBald/Avalonia86) by [notBald](https://github.com/notBald) (Windows and Linux) * [sl86](https://github.com/DDXofficial/sl86) by [DDX](https://github.com/DDXofficial) (Command-line 86Box machine manager written in Python) * [Linbox-qt5](https://github.com/Dungeonseeker/linbox-qt5) by [Dungeonseeker](https://github.com/Dungeonseeker/) (Linux focused, should work on Windows though untested) * [MacBox for 86Box](https://github.com/Moonif/MacBox) by [Moonif](https://github.com/Moonif) (MacOS only) diff --git a/src/86box.c b/src/86box.c index 85cbb9957..97c211bee 100644 --- a/src/86box.c +++ b/src/86box.c @@ -254,14 +254,9 @@ static volatile atomic_int pause_ack = 0; #ifndef RELEASE_BUILD -#define LOG_SIZE_BUFFER 1024 /* Log size buffer */ -#define LOG_SIZE_BUFFER_CYCLIC_LINES 32 /* Cyclic log size buffer (number of lines that should be cehcked) */ -#define LOG_MINIMUM_REPEAT_ORDER 4 /* Minimum repeat size */ +#define LOG_SIZE_BUFFER 1024 /* Log size buffer */ static char buff[LOG_SIZE_BUFFER]; -static char cyclic_buff[LOG_SIZE_BUFFER_CYCLIC_LINES][LOG_SIZE_BUFFER]; -static int32_t cyclic_last_line = 0; -static int32_t log_cycles = 0; static int seen = 0; @@ -322,112 +317,6 @@ pclog_ex(const char *fmt, va_list ap) } -/* -Starfrost, 7-8 January 2025: - -For RIVA 128 emulation I needed a way to suppress logging if a repeated pattern of the same set of lines were found. - -Implements a version of the Rabin-Karp algorithm https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm -*/ -void -pclog_ex_cyclic(const char* fmt, va_list ap) -{ -#ifndef RELEASE_BUILD - char temp[LOG_SIZE_BUFFER]; - - cyclic_last_line %= LOG_SIZE_BUFFER_CYCLIC_LINES; - - vsprintf(temp, fmt, ap); - - pclog_ensure_stdlog_open(); - - strncpy(cyclic_buff[cyclic_last_line], temp, LOG_SIZE_BUFFER); - - uint32_t hashes[LOG_SIZE_BUFFER_CYCLIC_LINES] = {0}; - - // Random numbers - uint32_t base = 257; - uint32_t mod = 1000000007; - - uint32_t repeat_order = 0; - bool is_cycle = false; - - // compute the set of hashes for the current log buffer - for (int32_t log_line = 0; log_line < LOG_SIZE_BUFFER_CYCLIC_LINES; log_line++) - { - if (cyclic_buff[log_line][0] == '\0') - continue; // skip - - for (int32_t log_line_char = 0; log_line_char < LOG_SIZE_BUFFER; log_line_char++) - { - hashes[log_line] = hashes[log_line] * base + cyclic_buff[log_line][log_line_char] % mod; - } - } - - - // Now see if there are real cycles... - // We implement a minimum repeat size. - for (int32_t check_size = LOG_MINIMUM_REPEAT_ORDER; check_size < LOG_SIZE_BUFFER_CYCLIC_LINES / 2; check_size++) - { - //TODO: Log what we need for cycle 1. - //TODO: Command line option that lets us turn off this behaviour. - for (int32_t log_line_to_check = 0; log_line_to_check < check_size; log_line_to_check++) - { - if (hashes[log_line_to_check] == hashes[(log_line_to_check + check_size) % LOG_SIZE_BUFFER_CYCLIC_LINES]) - { - repeat_order = check_size; - break; - } - } - - is_cycle = (repeat_order != 0); - - // if there still is a cycle.. - if (is_cycle) - break; - - } - - if (is_cycle) - { - if (cyclic_last_line % repeat_order == 0) - { - log_cycles++; - - if (log_cycles == 1) - { - // 'Replay' the last few log entries so they actually show up - // Todo: is this right? - - for (uint32_t index = cyclic_last_line - 1; index > (cyclic_last_line - repeat_order); index--) - { - // *very important* to prevent out of bounds index - uint32_t real_index = index % LOG_SIZE_BUFFER_CYCLIC_LINES; - fprintf(stdlog, "%s", cyclic_buff[real_index]); - - } - - fprintf(stdlog, "%s", temp); // allow normal logging - } - - - if (log_cycles > 1 && log_cycles < 100) - fprintf(stdlog, "***** Cyclical Log Repeat of Order %d #%d *****\n", repeat_order, log_cycles); - else if (log_cycles == 100) - fprintf(stdlog, "Logged the same cycle 100 times...shutting up until something interesting happens\n"); - } - } - else - { - log_cycles = 0; - fprintf(stdlog, "%s", temp); - } - - cyclic_last_line++; - -#endif - -} void pclog_toggle_suppr(void) diff --git a/src/cpu/808x.c b/src/cpu/808x.c index d815551ae..f37672a5c 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -1634,28 +1634,75 @@ cpu_data_opff_rm(void) } } +uint8_t +cpu_inb(uint16_t port) +{ + int old_cycles = cycles; + uint8_t ret; + + wait(is_mazovia ? 5 : 4, 1); + old_cycles = cycles; + + ret = inb(port); + + resub_cycles(old_cycles); + + return ret; +} + uint16_t cpu_inw(uint16_t port) { + int old_cycles = cycles; + uint16_t ret; + + wait(is_mazovia ? 5 : 4, 1); if (is8086 && !(port & 1)) { - wait(4, 0); + old_cycles = cycles; + ret = inw(port); } else { - wait(8, 0); + wait(is_mazovia ? 5 : 4, 1); + old_cycles = cycles; + ret = inb(port++); + ret |= (inb(port) << 8); } - return inw(port); + resub_cycles(old_cycles); + + return ret; +} + +void +cpu_outb(uint16_t port, uint16_t val) +{ + int old_cycles = cycles; + + wait(is_mazovia ? 5 : 4, 1); + old_cycles = cycles; + + outb(port, val); + + resub_cycles(old_cycles); } void cpu_outw(uint16_t port, uint16_t val) { + int old_cycles = cycles; + + wait(is_mazovia ? 5 : 4, 1); + if (is8086 && !(port & 1)) { - wait(4, 0); + old_cycles = cycles; + outw(port, val); } else { - wait(8, 0); + wait(is_mazovia ? 5 : 4, 1); + old_cycles = cycles; + outb(port++, val); + outb(port, val >> 8); } - return outw(port, val); + resub_cycles(old_cycles); } /* Executes instructions up to the specified number of cycles. */ @@ -1804,8 +1851,7 @@ execx86(int cycs) writememw(es, DI, cpu_inw(DX)); DI += (cpu_state.flags & D_FLAG) ? -2 : 2; } else { - wait(4, 0); - writememb(es, DI, inb(DX)); + writememb(es, DI, cpu_inb(DX)); DI += (cpu_state.flags & D_FLAG) ? -1 : 1; } @@ -1833,8 +1879,7 @@ execx86(int cycs) cpu_outw(DX, readmemw(dest_seg, SI)); SI += (cpu_state.flags & D_FLAG) ? -2 : 2; } else { - wait(4, 0); - outb(DX, readmemb(dest_seg + SI)); + cpu_outb(DX, readmemb(dest_seg + SI)); SI += (cpu_state.flags & D_FLAG) ? -1 : 1; } if (in_rep == 0) diff --git a/src/cpu/x86_ops_amd.h b/src/cpu/x86_ops_amd.h index 9e6bcce55..54da4a79d 100644 --- a/src/cpu/x86_ops_amd.h +++ b/src/cpu/x86_ops_amd.h @@ -22,12 +22,8 @@ opSYSCALL(uint32_t fetchdat) ret = syscall_op(fetchdat); - if (ret <= 1) { - CLOCK_CYCLES(20); - PREFETCH_RUN(20, 7, -1, 0, 0, 0, 0, 0); - PREFETCH_FLUSH(); + if (ret <= 1) CPU_BLOCK_END(); - } return ret; } @@ -41,12 +37,8 @@ opSYSRET(uint32_t fetchdat) ret = sysret(fetchdat); - if (ret <= 1) { - CLOCK_CYCLES(20); - PREFETCH_RUN(20, 7, -1, 0, 0, 0, 0, 0); - PREFETCH_FLUSH(); + if (ret <= 1) CPU_BLOCK_END(); - } return ret; } diff --git a/src/cpu/x86_ops_i686.h b/src/cpu/x86_ops_i686.h index 5e5dc3c7c..a67571875 100644 --- a/src/cpu/x86_ops_i686.h +++ b/src/cpu/x86_ops_i686.h @@ -18,12 +18,8 @@ opSYSENTER(uint32_t fetchdat) { int ret = sysenter(fetchdat); - if (ret <= 1) { - CLOCK_CYCLES(20); - PREFETCH_RUN(20, 7, -1, 0, 0, 0, 0, 0); - PREFETCH_FLUSH(); + if (ret <= 1) CPU_BLOCK_END(); - } return ret; } @@ -33,12 +29,8 @@ opSYSEXIT(uint32_t fetchdat) { int ret = sysexit(fetchdat); - if (ret <= 1) { - CLOCK_CYCLES(20); - PREFETCH_RUN(20, 7, -1, 0, 0, 0, 0, 0); - PREFETCH_FLUSH(); + if (ret <= 1) CPU_BLOCK_END(); - } return ret; } @@ -118,7 +110,8 @@ sf_fx_save_stor_common(uint32_t fetchdat, int bits) fpu_state.swd &= ~(FPU_SW_Summary | FPU_SW_Backward); } - CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + // CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + CLOCK_CYCLES(1); } else { /* FXSAVE */ writememw(easeg, cpu_state.eaaddr, i387_get_control_word()); @@ -163,7 +156,7 @@ sf_fx_save_stor_common(uint32_t fetchdat, int bits) writememw(easeg, cpu_state.eaaddr + (index * 16) + 40, fp.signExp); } - CLOCK_CYCLES((cr0 & 1) ? 56 : 67); + CLOCK_CYCLES(1); } return cpu_state.abrt; @@ -327,7 +320,8 @@ fx_save_stor_common(uint32_t fetchdat, int bits) } } - CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + // CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + CLOCK_CYCLES(1); } else { /* FXSAVE */ if ((twd & 0x0003) != 0x0003) @@ -372,7 +366,7 @@ fx_save_stor_common(uint32_t fetchdat, int bits) cpu_state.eaaddr = old_eaaddr; - CLOCK_CYCLES((cr0 & 1) ? 56 : 67); + CLOCK_CYCLES(1); } return cpu_state.abrt; @@ -400,8 +394,7 @@ static int opHINT_NOP_a16(uint32_t fetchdat) { fetch_ea_16(fetchdat); - CLOCK_CYCLES((is486) ? 1 : 3); - PREFETCH_RUN(3, 1, -1, 0, 0, 0, 0, 0); + CLOCK_CYCLES(1); return 0; } @@ -409,7 +402,6 @@ static int opHINT_NOP_a32(uint32_t fetchdat) { fetch_ea_32(fetchdat); - CLOCK_CYCLES((is486) ? 1 : 3); - PREFETCH_RUN(3, 1, -1, 0, 0, 0, 0, 0); + CLOCK_CYCLES(1); return 0; } diff --git a/src/device/kbc_at.c b/src/device/kbc_at.c index 5c3c9ac6e..74be59017 100644 --- a/src/device/kbc_at.c +++ b/src/device/kbc_at.c @@ -2127,6 +2127,13 @@ kbc_at_write(uint16_t port, uint8_t val, void *priv) } else if (fast_reset && ((val & 0xf0) == 0xf0)) { pulse_output(dev, val & 0x0f); + dev->state = STATE_MAIN_IBF; + return; + } else if (val == 0xae) { + /* Fast track it because of the LG MultiNet. */ + kbc_at_log("ATkbc: enable keyboard\n"); + set_enable_kbd(dev, 1); + dev->state = STATE_MAIN_IBF; return; } diff --git a/src/disk/hdd.c b/src/disk/hdd.c index b861b5e50..5243f016b 100644 --- a/src/disk/hdd.c +++ b/src/disk/hdd.c @@ -448,9 +448,13 @@ static hdd_preset_t hdd_speed_presets[] = { { .name = "[ATA-2] Quantum Fireball 640AT", .internal_name = "FB64A341", .model = "QUANTUM FIREBALL 640AT", .zones = 2, .avg_spt = 120, .heads = 2, .rpm = 5400, .full_stroke_ms = 24, .track_seek_ms = 3.1, .rcache_num_seg = 4, .rcache_seg_size = 128, .max_multiple = 8 }, { .name = "[ATA-2] Quantum Fireball TM1080AT", .internal_name = "TM10A462", .model = "QUANTUM FIREBALL TM1.0A", .zones = 2, .avg_spt = 120, .heads = 2, .rpm = 4500, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 8 }, { .name = "[ATA-2] Quantum Fireball TM1.2AT", .internal_name = "TM12A012", .model = "QUANTUM FIREBALL TM1.2A", .zones = 4, .avg_spt = 120, .heads = 2, .rpm = 4500, .full_stroke_ms = 21, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 8 }, + { .name = "[ATA-2] Quantum Fireball SE8.4A", .internal_name = "SE84A011", .model = "QUANTUM FIREBALL SE8.4A", .zones = 4, .avg_spt = 100, .heads = 8, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, + { .name = "[ATA-2] Quantum Fireball SE6.4A", .internal_name = "SE64A011", .model = "QUANTUM FIREBALL SE6.4A", .zones = 3, .avg_spt = 100, .heads = 6, .rpm = 5400, .full_stroke_ms = 20, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-2] Quantum Fireball ST3.2AT", .internal_name = "ST32A461", .model = "QUANTUM FIREBALL ST3.2A", .zones = 4, .avg_spt = 100, .heads = 4, .rpm = 5400, .full_stroke_ms = 21, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, - { .name = "[ATA-2] Quantum Fireball CR4.3AT", .internal_name = "CR43A013", .model = "QUANTUM FIREBALL CR4.3A", .zones = 2, .avg_spt = 110, .heads = 2, .rpm = 5400, .full_stroke_ms = 22, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, - { .name = "[ATA-2] Quantum Fireball EX5.1AT", .internal_name = "EX51A012", .model = "QUANTUM FIREBALL EX5.1A", .zones = 8, .avg_spt = 110, .heads = 4, .rpm = 5400, .full_stroke_ms = 22, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-2] Quantum Fireball CR4.3AT", .internal_name = "CR43A013", .model = "QUANTUM FIREBALL CR4.3A", .zones = 2, .avg_spt = 110, .heads = 3, .rpm = 5400, .full_stroke_ms = 22, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-2] Quantum Fireball EX5.1A", .internal_name = "EX51A012", .model = "QUANTUM FIREBALL EX5.1A", .zones = 8, .avg_spt = 110, .heads = 4, .rpm = 5400, .full_stroke_ms = 22, .track_seek_ms = 2.5, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-2] Quantum Fireball EX10.2A", .internal_name = "EX10A011", .model = "QUANTUM FIREBALL EX10.2A", .zones = 3, .avg_spt = 110, .heads = 6, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, + { .name = "[ATA-2] Quantum Fireball EX12.7A", .internal_name = "EX12A011", .model = "QUANTUM FIREBALL EX12.7A", .zones = 4, .avg_spt = 110, .heads = 8, .rpm = 5400, .full_stroke_ms = 18, .track_seek_ms = 2, .rcache_num_seg = 8, .rcache_seg_size = 512, .max_multiple = 16 }, { .name = "[ATA-2] Samsung PLS-31274A", .internal_name = "PLS31274A", .model = "SAMSUNG PLS-31274A", .zones = 4, .avg_spt = 110, .heads = 4, .rpm = 4500, .full_stroke_ms = 45, .track_seek_ms = 4.5, .rcache_num_seg = 4, .rcache_seg_size = 256, .max_multiple = 8 }, { .name = "[ATA-2] Samsung Winner-1", .internal_name = "WNR31601A", .model = "SAMSUNG WNR-31601A", .zones = 8, .avg_spt = 110, .heads = 4, .rpm = 5400, .full_stroke_ms = 22, .track_seek_ms = 3, .rcache_num_seg = 8, .rcache_seg_size = 128, .max_multiple = 16 }, { .name = "[ATA-2] Seagate Medalist (ST3780A)", .internal_name = "ST3780A", .model = "ST3780A", .zones = 8, .avg_spt = 120, .heads = 4, .rpm = 4500, .full_stroke_ms = 25, .track_seek_ms = 3.5, .rcache_num_seg = 4, .rcache_seg_size = 256, .max_multiple = 16 }, diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 266958410..96aeb645c 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -188,7 +188,6 @@ extern int config_changed; /* config has changed */ /* Function prototypes. */ #ifdef HAVE_STDARG_H extern void pclog_ex(const char *fmt, va_list ap); -extern void pclog_ex_cyclic(const char* fmt, va_list ap); extern void fatal_ex(const char *fmt, va_list ap); #endif extern void pclog_toggle_suppr(void); diff --git a/src/include/86box/log.h b/src/include/86box/log.h index 9d3568069..7f0b96d60 100644 --- a/src/include/86box/log.h +++ b/src/include/86box/log.h @@ -12,9 +12,11 @@ * * Authors: Miran Grca, * Fred N. van Kempen, + * Connor Hyde * * Copyright 2021 Miran Grca. * Copyright 2021 Fred N. van Kempen. + * Copyright 2025 Connor Hyde. */ #ifndef EMU_LOG_H @@ -26,11 +28,16 @@ extern "C" { # endif +#define LOG_SIZE_BUFFER 1024 /* Log size buffer */ +#define LOG_SIZE_BUFFER_CYCLIC_LINES 32 /* Cyclic log size buffer (number of lines that should be cehcked) */ +#define LOG_MINIMUM_REPEAT_ORDER 4 /* Minimum repeat size */ + /* Function prototypes. */ extern void log_set_suppr_seen(void *priv, int suppr_seen); extern void log_set_dev_name(void *priv, char *dev_name); # ifdef HAVE_STDARG_H extern void log_out(void *priv, const char *fmt, va_list); +extern void log_out_cyclic(void* priv, const char *fmt, va_list); extern void log_fatal(void *priv, const char *fmt, ...); # endif extern void *log_open(char *dev_name); diff --git a/src/include/86box/scsi_ncr5380.h b/src/include/86box/scsi_ncr5380.h index 55692075b..09307fed6 100644 --- a/src/include/86box/scsi_ncr5380.h +++ b/src/include/86box/scsi_ncr5380.h @@ -104,6 +104,7 @@ typedef struct ncr_t { int state; int clear_req; int wait_data; + int wait_data_back; int wait_complete; int command_pos; int data_pos; diff --git a/src/log.c b/src/log.c index b5267d70b..a4d84e616 100644 --- a/src/log.c +++ b/src/log.c @@ -12,12 +12,15 @@ * * Authors: Miran Grca, * Fred N. van Kempen, - * + * Connor Hyde + * * Copyright 2021 Miran Grca. * Copyright 2021 Fred N. van Kempen. + * Copyright 2025 Connor Hyde. */ #include #include +#include #include #include #include @@ -36,13 +39,31 @@ #ifndef RELEASE_BUILD typedef struct log_t { - char buff[1024]; - char *dev_name; - int seen; - int suppr_seen; + char buff[1024]; + char *dev_name; + int seen; + int suppr_seen; + char cyclic_buff[LOG_SIZE_BUFFER_CYCLIC_LINES][LOG_SIZE_BUFFER]; // Cyclical log buffer. This is 32kb, might calloc? + int32_t cyclic_last_line; + int32_t log_cycles; } log_t; extern FILE *stdlog; /* file to log output to */ +// Functions only used in this translation unit +void log_ensure_stdlog_open(void); + +void +log_ensure_stdlog_open(void) +{ + if (stdlog == NULL) { + if (log_path[0] != '\0') { + stdlog = plat_fopen(log_path, "w"); + if (stdlog == NULL) + stdlog = stdout; + } else + stdlog = stdout; + } +} void log_set_suppr_seen(void *priv, int suppr_seen) @@ -91,14 +112,7 @@ log_out(void *priv, const char *fmt, va_list ap) if (strcmp(fmt, "") == 0) return; - if (stdlog == NULL) { - if (log_path[0] != '\0') { - stdlog = plat_fopen(log_path, "w"); - if (stdlog == NULL) - stdlog = stdout; - } else - stdlog = stdout; - } + log_ensure_stdlog_open(); vsprintf(temp, fmt, ap); if (log->suppr_seen && !strcmp(log->buff, temp)) @@ -117,6 +131,131 @@ log_out(void *priv, const char *fmt, va_list ap) fflush(stdlog); } + +/* +Starfrost, 7-8 January 2025: + +For RIVA 128 emulation I needed a way to suppress logging if a repeated pattern of the same set of lines were found. + +Implements a version of the Rabin-Karp algorithm https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm +*/ +void +log_out_cyclic(void* priv, const char* fmt, va_list ap) +{ +#ifndef RELEASE_BUILD + // get our new logging system instance. + log_t* log = (log_t*)priv; + + // does the log actually exist? + if (!log) + return; + + // is the string empty? + if (fmt[0] == '\0') + return; + + // ensure stdlog is open + log_ensure_stdlog_open(); + + char temp[LOG_SIZE_BUFFER] = {0}; + + log->cyclic_last_line %= LOG_SIZE_BUFFER_CYCLIC_LINES; + + vsprintf(temp, fmt, ap); + + log_copy(log, log->cyclic_buff[log->cyclic_last_line], temp, LOG_SIZE_BUFFER); + + uint32_t hashes[LOG_SIZE_BUFFER_CYCLIC_LINES] = {0}; + + // Random numbers + uint32_t base = 257; + uint32_t mod = 1000000007; + + uint32_t repeat_order = 0; + bool is_cycle = false; + + // compute the set of hashes for the current log buffer + for (int32_t log_line = 0; log_line < LOG_SIZE_BUFFER_CYCLIC_LINES; log_line++) + { + if (log->cyclic_buff[log_line][0] == '\0') + continue; // skip + + for (int32_t log_line_char = 0; log_line_char < LOG_SIZE_BUFFER; log_line_char++) + { + hashes[log_line] = hashes[log_line] * base + log->cyclic_buff[log_line][log_line_char] % mod; + } + } + + + // Now see if there are real cycles... + // We implement a minimum repeat size. + for (int32_t check_size = LOG_MINIMUM_REPEAT_ORDER; check_size < LOG_SIZE_BUFFER_CYCLIC_LINES / 2; check_size++) + { + //TODO: Log what we need for cycle 1. + //TODO: Command line option that lets us turn off this behaviour. + for (int32_t log_line_to_check = 0; log_line_to_check < check_size; log_line_to_check++) + { + if (hashes[log_line_to_check] == hashes[(log_line_to_check + check_size) % LOG_SIZE_BUFFER_CYCLIC_LINES]) + { + repeat_order = check_size; + break; + } + } + + is_cycle = (repeat_order != 0); + + // if there still is a cycle.. + if (is_cycle) + break; + + } + + if (is_cycle) + { + if (log->cyclic_last_line % repeat_order == 0) + { + log->log_cycles++; + + if (log->log_cycles == 1) + { + // 'Replay' the last few log entries so they actually show up + // Todo: is this right? + + for (uint32_t index = log->cyclic_last_line - 1; index > (log->cyclic_last_line - repeat_order); index--) + { + // *very important* to prevent out of bounds index + uint32_t real_index = index % LOG_SIZE_BUFFER_CYCLIC_LINES; + log_copy(log, temp, log->cyclic_buff[real_index], LOG_SIZE_BUFFER); + + fprintf(stdlog, "%s", log->cyclic_buff[real_index]); + + } + + // restore the original line + log_copy(log, temp, log->cyclic_buff[log->cyclic_last_line], LOG_SIZE_BUFFER); + + fprintf(stdlog, "%s", temp); // allow normal logging + } + + + if (log->log_cycles > 1 && log->log_cycles < 100) + fprintf(stdlog, "***** Cyclical Log Repeat of Order %d #%d *****\n", repeat_order, log->log_cycles); + else if (log->log_cycles == 100) + fprintf(stdlog, "Logged the same cycle 100 times...shutting up until something interesting happens\n"); + } + } + else + { + log->log_cycles = 0; + fprintf(stdlog, "%s", temp); + } + + log->cyclic_last_line++; + +#endif + +} + void log_fatal(void *priv, const char *fmt, ...) { @@ -145,6 +284,8 @@ log_open(char *dev_name) log->dev_name = dev_name; log->suppr_seen = 1; + log->cyclic_last_line = 0; + log->log_cycles = 0; return (void *) log; } diff --git a/src/machine/m_at_socket7.c b/src/machine/m_at_socket7.c index f80d2d421..2dbb83684 100644 --- a/src/machine/m_at_socket7.c +++ b/src/machine/m_at_socket7.c @@ -58,10 +58,6 @@ machine_at_acerv35n_init(const machine_t *model) return ret; machine_at_common_init_ex(model, 2); - /* Yes, it's called amstrad_mega_pc_nvr_device, but it's basically the - standard AT NVR, just initialized to 0x00's (perhaps that should be the - default behavior?). */ - device_add(&amstrad_megapc_nvr_device); pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); diff --git a/src/pic.c b/src/pic.c index 82905261a..fa7ff3662 100644 --- a/src/pic.c +++ b/src/pic.c @@ -17,6 +17,7 @@ * Copyright 2015-2020 Andrew Jenner. * Copyright 2016-2020 Miran Grca. */ +#include #include #include #include @@ -496,7 +497,7 @@ pic_read(uint16_t addr, void *priv) simply read whatever is currently on the data bus. */ } - pic_log("pic_read(%04X, %08X) = %02X\n", addr, priv, dev->data_bus); + pic_log("pic_read(%04X) = %02X\n", addr, dev->data_bus); return dev->data_bus; } diff --git a/src/scsi/scsi_ncr5380.c b/src/scsi/scsi_ncr5380.c index 527ff373f..e5dff88f8 100644 --- a/src/scsi/scsi_ncr5380.c +++ b/src/scsi/scsi_ncr5380.c @@ -197,20 +197,30 @@ ncr5380_bus_read(ncr_t *ncr) phase = (ncr->cur_bus & SCSI_PHASE_MESSAGE_IN); if (phase == SCSI_PHASE_DATA_IN) { - ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++]; - ncr->state = STATE_DATAIN; - ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP; + if ((ncr->dma_mode == DMA_IDLE) || ncr->dma_initiator_receive_ext || (ncr->wait_data_back == 1)) { + ncr5380_log("Phase Data In.\n"); + if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL)) + ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++]; + + ncr->state = STATE_DATAIN; + ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP; + } } else if (phase == SCSI_PHASE_DATA_OUT) { if (ncr->new_phase & BUS_IDLE) { ncr->state = STATE_IDLE; ncr->cur_bus &= ~BUS_BSY; - } else - ncr->state = STATE_DATAOUT; + } else { + if ((ncr->dma_mode == DMA_IDLE) || ncr->dma_send_ext || (ncr->wait_data_back == 1)) + ncr->state = STATE_DATAOUT; + } } else if (phase == SCSI_PHASE_STATUS) { + ncr5380_log("Phase Status.\n"); + ncr->wait_data_back = 0; ncr->cur_bus |= BUS_REQ; ncr->state = STATE_STATUS; ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(dev->status) | BUS_DBP; } else if (phase == SCSI_PHASE_MESSAGE_IN) { + ncr5380_log("Phase Message In.\n"); ncr->state = STATE_MESSAGEIN; ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(0) | BUS_DBP; } else if (phase == SCSI_PHASE_MESSAGE_OUT) { @@ -335,19 +345,22 @@ ncr5380_bus_update(ncr_t *ncr, int bus) if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { if (ncr->data_pos >= dev->buffer_length) { ncr->cur_bus &= ~BUS_REQ; + ncr5380_log("CMD Phase1 DataIn.\n"); scsi_device_command_phase1(dev); ncr->new_phase = SCSI_PHASE_STATUS; ncr->wait_data = 4; ncr->wait_complete = 8; } else { - ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++]; + if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL)) + ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++]; + ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ; if (ncr->dma_mode == DMA_IDLE) { /*If a data in command that is not read 6/10 has been issued*/ ncr->data_wait |= 1; - ncr5380_log("DMA mode idle in\n"); + ncr5380_log("DMA mode idle IN=%d.\n", ncr->data_pos); ncr->timer(ncr->priv, ncr->period); } else { - ncr5380_log("DMA mode IN.\n"); + ncr5380_log("DMA mode IN=%d.\n", ncr->data_pos); ncr->clear_req = 3; } @@ -359,7 +372,8 @@ ncr5380_bus_update(ncr_t *ncr, int bus) case STATE_DATAOUT: dev = &scsi_devices[ncr->bus][ncr->target_id]; if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) { - dev->sc->temp_buffer[ncr->data_pos++] = BUS_GETDATA(bus); + if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL)) + dev->sc->temp_buffer[ncr->data_pos++] = BUS_GETDATA(bus); if (ncr->data_pos >= dev->buffer_length) { ncr->cur_bus &= ~BUS_REQ; @@ -439,12 +453,12 @@ ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr) switch (port & 7) { case 0: /* Output data register */ - ncr5380_log("Write: Output data register, val = %02x\n", val); + ncr5380_log("[%04X:%08X]: Write: Output data register, val=%02x\n", CS, cpu_state.pc, val); ncr->output_data = val; break; case 1: /* Initiator Command Register */ - ncr5380_log("Write: Initiator command register\n"); + ncr5380_log("[%04X:%08X]: Write: Initiator command register, val=%02x.\n", CS, cpu_state.pc, val); if ((val & 0x80) && !(ncr->icr & 0x80)) { ncr5380_log("Resetting the 5380\n"); ncr5380_reset(ncr); @@ -465,7 +479,7 @@ ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr) break; case 3: /* Target Command Register */ - ncr5380_log("Write: Target Command register\n"); + ncr5380_log("Write: Target Command register, val=%02x.\n", val); ncr->tcr = val; break; @@ -482,7 +496,7 @@ ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr) break; case 7: /* start DMA Initiator Receive */ - ncr5380_log("Write: start DMA initiator receive register, dma? = %02x\n", ncr->mode & MODE_DMA); + ncr5380_log("[%04X:%08X]: Write: start DMA initiator receive register, dma? = %02x\n", CS, cpu_state.pc, ncr->mode & MODE_DMA); /*a Read 6/10 has occurred, start the timer when the block count is loaded*/ ncr->dma_mode = DMA_INITIATOR_RECEIVE; if (ncr->dma_initiator_receive_ext) @@ -510,13 +524,13 @@ ncr5380_read(uint16_t port, ncr_t *ncr) ncr5380_log("Read: Current SCSI data register\n"); if (ncr->icr & ICR_DBP) { /*Return the data from the output register if on data bus phase from ICR*/ - ncr5380_log("Data Bus Phase, ret = %02x\n", ncr->output_data); ret = ncr->output_data; + ncr5380_log("[%04X:%08X]: Data Bus Phase, ret=%02x, clearreq=%d, waitdata=%x.\n", CS, cpu_state.pc, ret, ncr->clear_req, ncr->wait_data); } else { /*Return the data from the SCSI bus*/ ncr5380_bus_read(ncr); - ncr5380_log("NCR GetData=%02x\n", BUS_GETDATA(ncr->cur_bus)); ret = BUS_GETDATA(ncr->cur_bus); + ncr5380_log("[%04X:%08X]: NCR Get SCSI bus data=%02x.\n", CS, cpu_state.pc, ret); } break; @@ -595,7 +609,9 @@ ncr5380_read(uint16_t port, ncr_t *ncr) break; case 6: - ret = ncr->tx_data; + ncr5380_log("Read: Input Data.\n"); + ncr5380_bus_read(ncr); + ret = BUS_GETDATA(ncr->cur_bus); break; case 7: /* reset Parity/Interrupt */ diff --git a/src/scsi/scsi_ncr53c400.c b/src/scsi/scsi_ncr53c400.c index 6622ec59a..e028c7b42 100644 --- a/src/scsi/scsi_ncr53c400.c +++ b/src/scsi/scsi_ncr53c400.c @@ -148,6 +148,12 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv) ncr400->busy = 1; if (!(ncr->mode & MODE_MONITOR_BUSY) && ((scsi_device_get_callback(dev) > 0.0))) timer_on_auto(&ncr400->timer, ncr->period / 250.0); + else if ((ncr->mode & MODE_MONITOR_BUSY) && !ncr->wait_data) { + if (scsi_device_get_callback(dev) > 0.0) + timer_on_auto(&ncr400->timer, 100.0); + else + timer_on_auto(&ncr400->timer, 40.0); + } } } break; @@ -181,13 +187,15 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv) if ((ncr->mode & MODE_DMA) && (dev->buffer_length > 0)) { memset(ncr400->buffer, 0, MIN(128, dev->buffer_length)); if (ncr->mode & MODE_MONITOR_BUSY) - timer_on_auto(&ncr400->timer, ncr->period); + timer_on_auto(&ncr400->timer, (ncr->period / 4.0) * 3.0); else if (scsi_device_get_callback(dev) > 0.0) timer_on_auto(&ncr400->timer, 40.0); else timer_on_auto(&ncr400->timer, ncr->period); - ncr53c400_log("DMA timer on=%02x, callback=%lf, scsi buflen=%d, waitdata=%d, waitcomplete=%d, clearreq=%d, datawait=%d, enabled=%d.\n", ncr->mode & MODE_MONITOR_BUSY, scsi_device_get_callback(dev), dev->buffer_length, ncr->wait_complete, ncr->wait_data, ncr->wait_complete, ncr->clear_req, ncr->data_wait, timer_is_enabled(&ncr400->timer)); + ncr->wait_data_back = ncr->wait_data; + ncr53c400_log("DMA timer on=%02x, callback=%lf, scsi buflen=%d, waitdata=%d, waitcomplete=%d, clearreq=%d, datawait=%d, enabled=%d.\n", + ncr->mode & MODE_MONITOR_BUSY, scsi_device_get_callback(dev), dev->buffer_length, ncr->wait_data, ncr->wait_complete, ncr->clear_req, ncr->data_wait, timer_is_enabled(&ncr400->timer)); } break; @@ -244,6 +252,12 @@ ncr53c400_read(uint32_t addr, void *priv) ncr53c400_log("Transfer busy read, status = %02x.\n", ncr400->status_ctrl); if (!(ncr->mode & MODE_MONITOR_BUSY) && (scsi_device_get_callback(dev) > 0.0)) timer_on_auto(&ncr400->timer, ncr->period / 250.0); + else if ((ncr->mode & MODE_MONITOR_BUSY) && !ncr->wait_data) { + if (scsi_device_get_callback(dev) > 0.0) + timer_on_auto(&ncr400->timer, 100.0); + else + timer_on_auto(&ncr400->timer, 40.0); + } } } break; @@ -397,16 +411,20 @@ t130b_in(uint16_t port, void *priv) } static void -ncr53c400_dma_mode_ext(void *priv, UNUSED(void *ext_priv)) +ncr53c400_dma_mode_ext(void *priv, void *ext_priv) { - ncr_t *ncr = (ncr_t *) priv; + ncr53c400_t *ncr400 = (ncr53c400_t *) ext_priv; + ncr_t *ncr = (ncr_t *) priv; /*When a pseudo-DMA transfer has completed (Send or Initiator Receive), mark it as complete and idle the status*/ - if (!(ncr->mode & MODE_DMA)) { - ncr53c400_log("No DMA mode\n"); - ncr->tcr &= ~TCR_LAST_BYTE_SENT; - ncr->isr &= ~STATUS_END_OF_DMA; - ncr->dma_mode = DMA_IDLE; + ncr53c400_log("BlockCountLoaded=%d.\n", ncr400->block_count_loaded); + if (!ncr400->block_count_loaded) { + if (!(ncr->mode & MODE_DMA)) { + ncr53c400_log("No DMA mode\n"); + ncr->tcr &= ~TCR_LAST_BYTE_SENT; + ncr->isr &= ~STATUS_END_OF_DMA; + ncr->dma_mode = DMA_IDLE; + } } } @@ -474,6 +492,7 @@ ncr53c400_callback(void *priv) ncr400->block_count = (ncr400->block_count - 1) & 0xff; ncr53c400_log("NCR 53c400 Remaining blocks to be written=%d\n", ncr400->block_count); if (!ncr400->block_count) { + ncr->dma_mode = DMA_IDLE; ncr400->block_count_loaded = 0; ncr53c400_log("IO End of write transfer\n"); ncr->tcr |= TCR_LAST_BYTE_SENT; @@ -527,6 +546,7 @@ ncr53c400_callback(void *priv) ncr400->block_count = (ncr400->block_count - 1) & 0xff; ncr53c400_log("NCR 53c400 Remaining blocks to be read=%d\n", ncr400->block_count); if (!ncr400->block_count) { + ncr->dma_mode = DMA_IDLE; ncr400->block_count_loaded = 0; ncr53c400_log("IO End of read transfer\n"); ncr->isr |= STATUS_END_OF_DMA; @@ -544,6 +564,7 @@ ncr53c400_callback(void *priv) break; } + ncr53c400_log("Bus Read.\n"); ncr5380_bus_read(ncr); if (!(ncr->cur_bus & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) {