diff --git a/src/86box.c b/src/86box.c index 93ab491bc..67ad29297 100644 --- a/src/86box.c +++ b/src/86box.c @@ -1578,12 +1578,22 @@ pc_send_cae(void) extern void softresetx86(void); extern void hardresetx86(void); + extern void biu_set_bus_cycle(int bus_cycle); + extern void biu_set_bus_state(int bus_state); + extern void biu_set_bus_next_state(int bus_next_state); + extern void biu_set_cycle_t1(void); + extern void biu_set_next_cycle(void); + extern int biu_get_bus_cycle(void); + extern int biu_get_bus_state(void); + extern int biu_get_bus_next_state(void); extern void prefetch_queue_set_pos(int pos); extern void prefetch_queue_set_ip(uint16_t ip); - extern void prefetch_queue_set_prefetching(int p); + extern void prefetch_queue_set_in(uint16_t in); + extern void prefetch_queue_set_suspended(int p); extern int prefetch_queue_get_pos(void); extern uint16_t prefetch_queue_get_ip(void); - extern int prefetch_queue_get_prefetching(void); + extern uint16_t prefetch_queue_get_in(void); + extern int prefetch_queue_get_suspended(void); extern int prefetch_queue_get_size(void); */ static void diff --git a/src/cpu/386.c b/src/cpu/386.c index ed4b40ab2..7c352ea19 100644 --- a/src/cpu/386.c +++ b/src/cpu/386.c @@ -237,7 +237,7 @@ exec386_2386(int32_t cycs) cycles += cycs; while (cycles > 0) { - cycle_period = (timer_target - (uint32_t) tsc) + 1; + cycle_period = (timer_target - (uint64_t) tsc) + 1; x86_was_reset = 0; cycdiff = 0; @@ -411,7 +411,7 @@ block_ended: fatal("Life expired\n"); } - if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t) tsc)) + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint64_t) tsc)) timer_process(); #ifdef USE_GDBSTUB diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index 852c25427..c3ca9a8de 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -280,7 +280,7 @@ update_tsc(void) tsc += cycdiff; if (cycdiff > 0) { - if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t) tsc)) + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint64_t) tsc)) timer_process(); } } @@ -865,7 +865,7 @@ exec386_dynarec(int32_t cycs) } if (cycdiff > 0) { - if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t) tsc)) + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint64_t) tsc)) timer_process(); } @@ -894,7 +894,7 @@ exec386(int32_t cycs) cycles += cycs; while (cycles > 0) { - cycle_period = (timer_target - (uint32_t) tsc) + 1; + cycle_period = (timer_target - (uint64_t) tsc) + 1; x86_was_reset = 0; cycdiff = 0; @@ -1078,7 +1078,7 @@ block_ended: fatal("Life expired\n"); } - if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t) tsc)) + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint64_t) tsc)) timer_process(); #ifdef USE_GDBSTUB diff --git a/src/cpu/808x.c b/src/cpu/808x.c index 14e56f23a..4e2e830d0 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -272,7 +272,7 @@ clock_end(void) /* On 808x systems, clock speed is usually crystal frequency divided by an integer. */ tsc += (uint64_t) diff * ((uint64_t) xt_cpu_multi >> 32ULL); /* Shift xt_cpu_multi by 32 bits to the right and then multiply. */ - if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t) tsc)) + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint64_t) tsc)) timer_process(); } diff --git a/src/disk/hdd.c b/src/disk/hdd.c index bbbec0865..c323bf7e3 100644 --- a/src/disk/hdd.c +++ b/src/disk/hdd.c @@ -313,7 +313,7 @@ hdd_timing_write(hard_disk_t *hdd, uint32_t addr, uint32_t len) } } - hdd->cache.write_start_time = tsc + (uint32_t) (seek_time * cpuclock / 1000000.0); + hdd->cache.write_start_time = tsc + (uint64_t) (seek_time * cpuclock / 1000000.0); return seek_time; } @@ -383,7 +383,7 @@ update_lru: cache->ra_ongoing = 1; cache->ra_segment = active_seg->id; - cache->ra_start_time = tsc + (uint32_t) (seek_time * cpuclock / 1000000.0); + cache->ra_start_time = tsc + (uint64_t) (seek_time * cpuclock / 1000000.0); return seek_time; } diff --git a/src/include/86box/timer.h b/src/include/86box/timer.h index 37a03d9ca..a5ecf72fc 100644 --- a/src/include/86box/timer.h +++ b/src/include/86box/timer.h @@ -1,6 +1,14 @@ #ifndef _TIMER_H_ #define _TIMER_H_ +#ifndef int128_t +#define int128_t __int128 +#endif + +#ifndef uint128_t +#define uint128_t unsigned __int128 +#endif + extern uint64_t tsc; /* Maximum period, currently 1 second. */ @@ -11,18 +19,6 @@ extern uint64_t tsc; #define TIMER_SPLIT 2 #define TIMER_ENABLED 1 -#pragma pack(push, 1) -typedef struct ts_struct_t { - uint32_t frac; - uint32_t integer; -} ts_struct_t; -#pragma pack(pop) - -typedef union ts_t { - uint64_t ts64; - ts_struct_t ts32; -} ts_t; - /*Timers are based on the CPU Time Stamp Counter. Timer timestamps are in a 32:32 fixed point format, with the integer part compared against the TSC. The fractional part is used when advancing the timestamp to ensure a more accurate @@ -36,12 +32,8 @@ typedef union ts_t { to repeat, the callback must call timer_advance_u64(). This is a change from the old timer API.*/ typedef struct pc_timer_t { -#ifdef USE_PCEM_TIMER - uint32_t ts_integer; + uint64_t ts_integer; uint32_t ts_frac; -#else - ts_t ts; -#endif int flags; /* The flags are defined above. */ int in_callback; double period; /* This is used for large period timers to count @@ -60,7 +52,7 @@ extern "C" { /*Timestamp of nearest enabled timer. CPU emulation must call timer_process() when TSC matches or exceeds this.*/ -extern uint32_t timer_target; +extern uint64_t timer_target; /*Enable timer, without updating timestamp*/ extern void timer_enable(pc_timer_t *timer); @@ -82,18 +74,33 @@ extern void timer_add(pc_timer_t *timer, void (*callback)(void *priv), void *pri extern uint64_t TIMER_USEC; /*True if timer a expires before timer b*/ -#define TIMER_LESS_THAN(a, b) ((int64_t) ((a)->ts.ts64 - (b)->ts.ts64) <= 0) +#define TIMER_LESS_THAN(a, b) ((int64_t) ((a)->ts_integer - (b)->ts_integer) <= 0) /*True if timer a expires before 32 bit integer timestamp b*/ -#define TIMER_LESS_THAN_VAL(a, b) ((int32_t) ((a)->ts.ts32.integer - (b)) <= 0) +#define TIMER_LESS_THAN_VAL(a, b) ((int64_t) ((a)->ts_integer - (b)) <= 0) /*True if 32 bit integer timestamp a expires before 32 bit integer timestamp b*/ -#define TIMER_VAL_LESS_THAN_VAL(a, b) ((int32_t) ((a) - (b)) <= 0) +#define TIMER_VAL_LESS_THAN_VAL(a, b) ((int64_t) ((a) - (b)) <= 0) + +#ifndef printf +#include +#endif /*Advance timer by delay, specified in 32:32 format. This should be used to resume a recurring timer in a callback routine*/ static __inline void timer_advance_u64(pc_timer_t *timer, uint64_t delay) { - timer->ts.ts64 += delay; + uint64_t int_delay = delay >> 32; + uint32_t frac_delay = delay & 0xffffffff; + + if (int_delay & 0x0000000080000000ULL) { + printf("timer_advance_u64(): Negative delay: %08X%08X!\n", (uint32_t) (int_delay), frac_delay); + int_delay |= 0xffffffff00000000ULL; + } + + if ((frac_delay + timer->ts_frac) < frac_delay) + timer->ts_integer++; + timer->ts_frac += frac_delay; + timer->ts_integer += int_delay; timer_enable(timer); } @@ -103,9 +110,16 @@ timer_advance_u64(pc_timer_t *timer, uint64_t delay) static __inline void timer_set_delay_u64(pc_timer_t *timer, uint64_t delay) { - timer->ts.ts64 = 0ULL; - timer->ts.ts32.integer = tsc; - timer->ts.ts64 += delay; + uint64_t int_delay = delay >> 32; + uint32_t frac_delay = delay & 0xffffffff; + + if (int_delay & 0x0000000080000000ULL) { + printf("timer_set_delay_u64(): Negative delay: %08X%08X!\n", (uint32_t) (int_delay), frac_delay); + int_delay |= 0xffffffff00000000ULL; + } + + timer->ts_frac = frac_delay; + timer->ts_integer = int_delay + (uint64_t)tsc; timer_enable(timer); } @@ -125,21 +139,19 @@ timer_is_on(pc_timer_t *timer) } /*Return integer timestamp of timer*/ -static __inline uint32_t +static __inline uint64_t timer_get_ts_int(pc_timer_t *timer) { - return timer->ts.ts32.integer; + return timer->ts_integer; } /*Return remaining time before timer expires, in us. If the timer has already expired then return 0*/ -static __inline uint32_t +static __inline uint64_t timer_get_remaining_us(pc_timer_t *timer) { - int64_t remaining; - if (timer->flags & TIMER_ENABLED) { - remaining = (int64_t) (timer->ts.ts64 - (uint64_t) (tsc << 32)); + int128_t remaining = (((uint128_t)timer->ts_integer << 32) | timer->ts_frac) - ((uint128_t)tsc << 32); if (remaining < 0) return 0; @@ -151,13 +163,11 @@ timer_get_remaining_us(pc_timer_t *timer) /*Return remaining time before timer expires, in 32:32 timestamp format. If the timer has already expired then return 0*/ -static __inline uint64_t +static __inline uint128_t timer_get_remaining_u64(pc_timer_t *timer) { - int64_t remaining; - if (timer->flags & TIMER_ENABLED) { - remaining = (int64_t) (timer->ts.ts64 - (uint64_t) (tsc << 32)); + int128_t remaining = (((uint128_t)timer->ts_integer << 32) | timer->ts_frac) - ((uint128_t)tsc << 32); if (remaining < 0) return 0; diff --git a/src/mem/mem.c b/src/mem/mem.c index 80803e6a2..91fa277be 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -668,7 +668,6 @@ read_mem_b(uint32_t addr) { mem_mapping_t *map; uint8_t ret = 0xff; - int old_cycles = cycles; mem_logical_addr = addr; addr &= rammask; @@ -677,8 +676,6 @@ read_mem_b(uint32_t addr) if (map && map->read_b) ret = map->read_b(addr, map->priv); - resub_cycles(old_cycles); - return ret; } @@ -687,7 +684,6 @@ read_mem_w(uint32_t addr) { mem_mapping_t *map; uint16_t ret = 0xffff; - int old_cycles = cycles; mem_logical_addr = addr; addr &= rammask; @@ -703,8 +699,6 @@ read_mem_w(uint32_t addr) ret = map->read_b(addr, map->priv) | (map->read_b(addr + 1, map->priv) << 8); } - resub_cycles(old_cycles); - return ret; } @@ -712,7 +706,6 @@ void write_mem_b(uint32_t addr, uint8_t val) { mem_mapping_t *map; - int old_cycles = cycles; mem_logical_addr = addr; addr &= rammask; @@ -720,15 +713,12 @@ write_mem_b(uint32_t addr, uint8_t val) map = write_mapping[addr >> MEM_GRANULARITY_BITS]; if (map && map->write_b) map->write_b(addr, val, map->priv); - - resub_cycles(old_cycles); } void write_mem_w(uint32_t addr, uint16_t val) { mem_mapping_t *map; - int old_cycles = cycles; mem_logical_addr = addr; addr &= rammask; @@ -747,8 +737,6 @@ write_mem_w(uint32_t addr, uint16_t val) } } } - - resub_cycles(old_cycles); } uint8_t diff --git a/src/mem/nmc93cxx.c b/src/mem/nmc93cxx.c index 17d97591e..8f958fa5e 100644 --- a/src/mem/nmc93cxx.c +++ b/src/mem/nmc93cxx.c @@ -29,6 +29,7 @@ #include <86box/nmc93cxx.h> #include <86box/plat_unused.h> +#define ENABLE_NMC93CXX_EEPROM_LOG 1 #ifdef ENABLE_NMC93CXX_EEPROM_LOG int nmc93cxx_eeprom_do_log = ENABLE_NMC93CXX_EEPROM_LOG; diff --git a/src/timer.c b/src/timer.c index 03908890f..9f47f8608 100644 --- a/src/timer.c +++ b/src/timer.c @@ -8,7 +8,7 @@ #include <86box/nv/vid_nv_rivatimer.h> uint64_t TIMER_USEC; -uint32_t timer_target; +uint64_t timer_target; /*Enabled timers are stored in a linked list, with the first timer to expire at the head.*/ @@ -23,68 +23,55 @@ void timer_enable(pc_timer_t *timer) { pc_timer_t *timer_node = timer_head; - int ret = 0; - - if (!timer_inited || (timer == NULL)) - return; if (timer->flags & TIMER_ENABLED) timer_disable(timer); if (timer->next || timer->prev) - fatal("timer_disable(): Attempting to enable a non-isolated " - "timer incorrectly marked as disabled\n"); + fatal("timer_enable - timer->next\n"); + + timer->flags |= TIMER_ENABLED; /*List currently empty - add to head*/ if (!timer_head) { - timer_head = timer; + timer_head = timer; timer->next = timer->prev = NULL; - timer_target = timer_head->ts.ts32.integer; - ret = 1; - } else if (TIMER_LESS_THAN(timer, timer_head)) { - timer->next = timer_head; - timer->prev = NULL; - timer_head->prev = timer; - timer_head = timer; - timer_target = timer_head->ts.ts32.integer; - ret = 1; - } else if (!timer_head->next) { - timer_head->next = timer; - timer->prev = timer_head; - ret = 1; + timer_target = timer_head->ts_integer; + return; } - if (ret == 0) { - pc_timer_t *prev = timer_head; - timer_node = timer_head->next; + timer_node = timer_head; - while (1) { - /*Timer expires before timer_node. Add to list in front of timer_node*/ - if (TIMER_LESS_THAN(timer, timer_node)) { - timer->next = timer_node; - timer->prev = prev; - timer_node->prev = timer; - prev->next = timer; - ret = 1; - break; + while (1) { + /* + Timer expires before timer_node. + Add to list in front of timer_node + */ + if (TIMER_LESS_THAN(timer, timer_node)) { + timer->next = timer_node; + timer->prev = timer_node->prev; + timer_node->prev = timer; + if (timer->prev) + timer->prev->next = timer; + else { + timer_head = timer; + timer_target = timer_head->ts_integer; } - - /*timer_node is last in the list. Add timer to end of list*/ - if (!timer_node->next) { - timer_node->next = timer; - timer->prev = timer_node; - ret = 1; - break; - } - - prev = timer_node; - timer_node = timer_node->next; + return; } - } - /* Do not mark it as enabled if it has failed every single condition. */ - if (ret == 1) - timer->flags |= TIMER_ENABLED; + /* + timer_node is last in the list. + Add timer to end of list + */ + if (!timer_node->next) { + timer_node->next = timer; + timer->prev = timer_node; + return; + } + + timer_node = timer_node->next; + } } void @@ -93,9 +80,12 @@ timer_disable(pc_timer_t *timer) if (!timer_inited || (timer == NULL) || !(timer->flags & TIMER_ENABLED)) return; - if (!timer->next && !timer->prev && timer != timer_head) + if (!timer->next && !timer->prev && timer != timer_head) { + uint32_t *p = NULL; + *p = 5; /* Crash deliberately. */ fatal("timer_disable(): Attempting to disable an isolated " "non-head timer incorrectly marked as enabled\n"); + } timer->flags &= ~TIMER_ENABLED; timer->in_callback = 0; @@ -109,41 +99,60 @@ timer_disable(pc_timer_t *timer) timer->prev = timer->next = NULL; } +static void +timer_remove_head(void) +{ + if (timer_head) { + pc_timer_t *timer = timer_head; + timer_head = timer->next; + timer_head->prev = NULL; + timer->next = timer->prev = NULL; + timer->flags &= ~TIMER_ENABLED; + } +} + void timer_process(void) { - pc_timer_t *timer; + int num = 0; if (!timer_head) return; + uint64_t old_target = timer_target; + while (1) { - timer = timer_head; + pc_timer_t *timer = timer_head; - if (!TIMER_LESS_THAN_VAL(timer, (uint32_t) tsc)) + if (!TIMER_LESS_THAN_VAL(timer, (uint64_t) tsc)) { + if (num == 0) + pclog("No processing because all timers expire later\n"); break; + } - timer_head = timer->next; - if (timer_head) - timer_head->prev = NULL; - - timer->next = timer->prev = NULL; - timer->flags &= ~TIMER_ENABLED; + timer_remove_head(); if (timer->flags & TIMER_SPLIT) timer_advance_ex(timer, 0); /* We're splitting a > 1 s period into - multiple <= 1 s periods. */ + multiple <= 1 s periods. */ else if (timer->callback != NULL) { - /* Make sure it's not NULL, so that we can + /* + Make sure it's not NULL, so that we can have a NULL callback when no operation - is needed. */ + is needed. + */ timer->in_callback = 1; timer->callback(timer->priv); timer->in_callback = 0; } + + num++; } - timer_target = timer_head->ts.ts32.integer; + timer_target = timer_head->ts_integer; + + if (old_target > timer_target) + pclog("Timer wraparound!\n"); } void @@ -200,7 +209,8 @@ timer_stop(pc_timer_t *timer) return; timer->period = 0.0; - timer_disable(timer); + if (timer->flags & TIMER_ENABLED) + timer_disable(timer); timer->flags &= ~TIMER_SPLIT; timer->in_callback = 0; } @@ -277,11 +287,11 @@ timer_set_new_tsc(uint64_t new_tsc) } timer = timer_head; - timer_target = new_tsc + (int32_t)(timer_get_ts_int(timer_head) - (uint32_t)tsc); + timer_target = new_tsc + (int64_t)(timer_get_ts_int(timer_head) - (uint64_t)tsc); while (timer) { - int32_t offset_from_current_tsc = (int32_t)(timer_get_ts_int(timer) - (uint32_t)tsc); - timer->ts.ts32.integer = new_tsc + offset_from_current_tsc; + int64_t offset_from_current_tsc = (int64_t)(timer_get_ts_int(timer) - (uint64_t)tsc); + timer->ts_integer = new_tsc + offset_from_current_tsc; timer = timer->next; } diff --git a/src/video/vid_cga.c b/src/video/vid_cga.c index f4c93e9c4..2cb5fe6fa 100644 --- a/src/video/vid_cga.c +++ b/src/video/vid_cga.c @@ -239,15 +239,23 @@ cga_recalctimings(cga_t *cga) if (cga->cgamode & CGA_MODE_FLAG_HIGHRES) { disptime = (double) (cga->crtc[CGA_CRTC_HTOTAL] + 1); _dispontime = (double) cga->crtc[CGA_CRTC_HDISP]; + if (_dispontime >= disptime) + _dispontime = disptime - 1; } else { disptime = (double) ((cga->crtc[CGA_CRTC_HTOTAL] + 1) << 1); _dispontime = (double) (cga->crtc[CGA_CRTC_HDISP] << 1); + if (_dispontime >= disptime) + _dispontime = disptime - 2; } _dispofftime = disptime - _dispontime; _dispontime = _dispontime * CGACONST; _dispofftime = _dispofftime * CGACONST; cga->dispontime = (uint64_t) (_dispontime); + if (cga->dispontime > 0x7fffffffffffffffULL) + pclog("CGA: Negative display on time (%i, %i, %i)\n", cga->cgamode & CGA_MODE_FLAG_HIGHRES, cga->crtc[CGA_CRTC_HTOTAL] + 1, cga->crtc[CGA_CRTC_HDISP]); cga->dispofftime = (uint64_t) (_dispofftime); + if (cga->dispofftime > 0x7fffffffffffffffULL) + pclog("CGA: Negative display off time (%i, %i, %i)\n", cga->cgamode & CGA_MODE_FLAG_HIGHRES, cga->crtc[CGA_CRTC_HTOTAL] + 1, cga->crtc[CGA_CRTC_HDISP]); } static void diff --git a/src/video/vid_genius.c b/src/video/vid_genius.c index 5dd3d2ade..0289e1104 100644 --- a/src/video/vid_genius.c +++ b/src/video/vid_genius.c @@ -329,12 +329,13 @@ genius_recalctimings(genius_t *genius) double disptime; double _dispontime; double _dispofftime; + double crtcconst = (cpuclock / 53216000.0 * (double) (1ULL << 32)) * 9.0; - disptime = 0x31; - _dispontime = 0x28; + disptime = 0x62; + _dispontime = 0x50; _dispofftime = disptime - _dispontime; - _dispontime *= MDACONST; - _dispofftime *= MDACONST; + _dispontime *= crtcconst; + _dispofftime *= crtcconst; genius->dispontime = (uint64_t) (_dispontime); genius->dispofftime = (uint64_t) (_dispofftime); }