mirror of
https://github.com/86Box/86Box.git
synced 2026-02-22 01:25:33 -07:00
Merge pull request #6696 from 86Box/64_32_timers
Rework timers to 64:32 timers (so split 96-bit) in order to reduce wraparounds.
This commit is contained in:
14
src/86box.c
14
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,31 @@ 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 <stdio.h>
|
||||
#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)
|
||||
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 +108,14 @@ 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)
|
||||
int_delay |= 0xffffffff00000000ULL;
|
||||
|
||||
timer->ts_frac = frac_delay;
|
||||
timer->ts_integer = int_delay + (uint64_t)tsc;
|
||||
|
||||
timer_enable(timer);
|
||||
}
|
||||
@@ -125,21 +135,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 +159,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;
|
||||
|
||||
@@ -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
|
||||
|
||||
134
src/timer.c
134
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,52 @@ 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;
|
||||
|
||||
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))
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -200,7 +201,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 +279,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;
|
||||
}
|
||||
|
||||
@@ -239,9 +239,13 @@ 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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -338,11 +338,11 @@ voodoo_readl(uint32_t addr, void *priv)
|
||||
break;
|
||||
case SST_hvRetrace:
|
||||
{
|
||||
uint32_t line_time = (uint32_t) (voodoo->line_time >> 32);
|
||||
uint32_t diff = (timer_get_ts_int(&voodoo->timer) > (tsc & 0xffffffff)) ? (timer_get_ts_int(&voodoo->timer) - (tsc & 0xffffffff)) : 0;
|
||||
uint32_t pre_div = diff * voodoo->h_total;
|
||||
uint32_t post_div = pre_div / line_time;
|
||||
uint32_t h_pos = (voodoo->h_total - 1) - post_div;
|
||||
uint64_t line_time = (uint64_t) (voodoo->line_time >> 32);
|
||||
uint64_t diff = (timer_get_ts_int(&voodoo->timer) > tsc) ? (timer_get_ts_int(&voodoo->timer) - tsc) : 0;
|
||||
uint64_t pre_div = diff * voodoo->h_total;
|
||||
uint64_t post_div = pre_div / line_time;
|
||||
uint64_t h_pos = (voodoo->h_total - 1) - post_div;
|
||||
|
||||
if (h_pos >= voodoo->h_total)
|
||||
h_pos = 0;
|
||||
|
||||
Reference in New Issue
Block a user