mirror of
https://github.com/86Box/86Box.git
synced 2026-02-24 02:18:20 -07:00
Merge remote-tracking branch 'mainline/master'
This commit is contained in:
@@ -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)
|
||||
|
||||
113
src/86box.c
113
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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -12,9 +12,11 @@
|
||||
*
|
||||
* Authors: Miran Grca, <mgrca8@gmail.com>
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Connor Hyde <mario64crashed@gmail.com, nomorestarfrost@gmail.com>
|
||||
*
|
||||
* 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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
167
src/log.c
167
src/log.c
@@ -12,12 +12,15 @@
|
||||
*
|
||||
* Authors: Miran Grca, <mgrca8@gmail.com>
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
* Connor Hyde <mario64crashed@gmail.com, nomorestarfrost@gmail.com>
|
||||
*
|
||||
* Copyright 2021 Miran Grca.
|
||||
* Copyright 2021 Fred N. van Kempen.
|
||||
* Copyright 2025 Connor Hyde.
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
* Copyright 2015-2020 Andrew Jenner.
|
||||
* Copyright 2016-2020 Miran Grca.
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
Reference in New Issue
Block a user