Rewrote handling of host time synchronisation. Amstrad machines now boot again.

Also fixed a bug where the emulated time ran 100x faster than expected.
This commit is contained in:
SarahW 2016-08-15 20:28:02 +01:00
commit 4e299a8038
3 changed files with 69 additions and 57 deletions

View file

@ -103,12 +103,11 @@ void nvr_onesec(void *p)
if (!(nvrram[RTC_REGB] & RTC_SET)) if (!(nvrram[RTC_REGB] & RTC_SET))
{ {
nvr_update_status = RTC_UIP; nvr_update_status = RTC_UIP;
/* If sync is disabled, move internal clock ahead by 1 second. */ rtc_tick();
if (!enable_sync)
rtc_tick();
nvr_update_end_count = (int)((244.0 + 1984.0) * TIMER_USEC); nvr_update_end_count = (int)((244.0 + 1984.0) * TIMER_USEC);
} }
nvr_onesec_cnt = 0;
} }
nvr_onesec_time += (int)(10000 * TIMER_USEC); nvr_onesec_time += (int)(10000 * TIMER_USEC);
} }
@ -241,7 +240,10 @@ void loadnvr()
return; return;
} }
fread(nvrram,128,1,f); fread(nvrram,128,1,f);
if (!enable_sync) time_update(nvrram, 0xFF); /* Update the internal clock state based on the NVR registers. */ if (enable_sync)
time_internal_sync(nvrram);
else
time_internal_set_nvrram(nvrram); /* Update the internal clock state based on the NVR registers. */
fclose(f); fclose(f);
nvrram[RTC_REGA] = 6; nvrram[RTC_REGA] = 6;
nvrram[RTC_REGB] = RTC_2412; nvrram[RTC_REGB] = RTC_2412;

114
src/rtc.c
View file

@ -124,22 +124,6 @@ void time_update(char *nvrram, int reg)
internal_clock.year %= 100; internal_clock.year %= 100;
internal_clock.year += (DCB(nvrram[RTC_CENTURY]) * 100); internal_clock.year += (DCB(nvrram[RTC_CENTURY]) * 100);
break; break;
case 0xFF: /* Load the entire internal clock state from the NVR. */
internal_clock.sec = (nvrram[RTC_REGB] & RTC_DM) ? nvrram[RTC_SECONDS] : DCB(nvrram[RTC_SECONDS]);
internal_clock.min = (nvrram[RTC_REGB] & RTC_DM) ? nvrram[RTC_MINUTES] : DCB(nvrram[RTC_MINUTES]);
temp = (nvrram[RTC_REGB] & RTC_DM) ? nvrram[RTC_HOURS] : DCB(nvrram[RTC_HOURS]);
if (nvrram[RTC_REGB] & RTC_2412)
internal_clock.hour = temp;
else
internal_clock.hour = ((temp & ~RTC_AMPM) % 12) + ((temp & RTC_AMPM) ? 12 : 0);
internal_clock.mday = (nvrram[RTC_REGB] & RTC_DM) ? nvrram[RTC_DOM] : DCB(nvrram[RTC_DOM]);
internal_clock.mon = (nvrram[RTC_REGB] & RTC_DM) ? nvrram[RTC_MONTH] : DCB(nvrram[RTC_MONTH]);
internal_clock.year = (nvrram[RTC_REGB] & RTC_DM) ? nvrram[RTC_YEAR] : DCB(nvrram[RTC_YEAR]);
internal_clock.year += (nvrram[RTC_REGB] & RTC_DM) ? 1900 : (DCB(nvrram[RTC_CENTURY]) * 100);
break;
} }
} }
@ -157,50 +141,31 @@ static int time_week_day()
} }
/* Called to get time into the internal clock */ /* Called to get time into the internal clock */
static void time_internal(struct tm **time_var) static void time_internal_get(struct tm *time_var)
{ {
if (*time_var == NULL) time_var->tm_sec = internal_clock.sec;
*time_var = (struct tm *)malloc(sizeof(struct tm)); time_var->tm_min = internal_clock.min;
time_var->tm_hour = internal_clock.hour;
(*time_var)->tm_sec = internal_clock.sec; time_var->tm_wday = time_week_day();
(*time_var)->tm_min = internal_clock.min; time_var->tm_mday = internal_clock.mday;
(*time_var)->tm_hour = internal_clock.hour; time_var->tm_mon = internal_clock.mon - 1;
(*time_var)->tm_wday = time_week_day(); time_var->tm_year = internal_clock.year - 1900;
(*time_var)->tm_mday = internal_clock.mday;
(*time_var)->tm_mon = internal_clock.mon - 1;
(*time_var)->tm_year = internal_clock.year - 1900;
} }
static time_t cur_time; static void time_internal_set(struct tm *time_var)
static struct tm *cur_time_tm; {
internal_clock.sec = time_var->tm_sec;
internal_clock.min = time_var->tm_min;
internal_clock.hour = time_var->tm_hour;
internal_clock.mday = time_var->tm_mday;
internal_clock.mon = time_var->tm_mon + 1;
internal_clock.year = time_var->tm_year + 1900;
}
/* Periodic RTC update function static void time_set_nvrram(char *nvrram, struct tm *cur_time_tm)
See also: nvr_onesec() in nvr.c
*/
void time_get(char *nvrram)
{ {
int dow, mon, year; int dow, mon, year;
if (enable_sync)
{
time(&cur_time);
/* Mingw doesn't support localtime_r */
#if __MINGW32__
cur_time_tm = localtime(&cur_time);
#else
#if __MINGW64__
cur_time_tm = localtime(&cur_time);
#else
localtime_r(&cur_time, &cur_time_tm);
#endif
#endif
}
else
{
time_internal(&cur_time_tm);
}
if (nvrram[RTC_REGB] & RTC_DM) if (nvrram[RTC_REGB] & RTC_DM)
{ {
nvrram[RTC_SECONDS] = cur_time_tm->tm_sec; nvrram[RTC_SECONDS] = cur_time_tm->tm_sec;
@ -242,3 +207,46 @@ void time_get(char *nvrram)
} }
} }
} }
void time_internal_set_nvrram(char *nvrram)
{
int temp;
/* Load the entire internal clock state from the NVR. */
internal_clock.sec = (nvrram[RTC_REGB] & RTC_DM) ? nvrram[RTC_SECONDS] : DCB(nvrram[RTC_SECONDS]);
internal_clock.min = (nvrram[RTC_REGB] & RTC_DM) ? nvrram[RTC_MINUTES] : DCB(nvrram[RTC_MINUTES]);
temp = (nvrram[RTC_REGB] & RTC_DM) ? nvrram[RTC_HOURS] : DCB(nvrram[RTC_HOURS]);
if (nvrram[RTC_REGB] & RTC_2412)
internal_clock.hour = temp;
else
internal_clock.hour = ((temp & ~RTC_AMPM) % 12) + ((temp & RTC_AMPM) ? 12 : 0);
internal_clock.mday = (nvrram[RTC_REGB] & RTC_DM) ? nvrram[RTC_DOM] : DCB(nvrram[RTC_DOM]);
internal_clock.mon = (nvrram[RTC_REGB] & RTC_DM) ? nvrram[RTC_MONTH] : DCB(nvrram[RTC_MONTH]);
internal_clock.year = (nvrram[RTC_REGB] & RTC_DM) ? nvrram[RTC_YEAR] : DCB(nvrram[RTC_YEAR]);
internal_clock.year += (nvrram[RTC_REGB] & RTC_DM) ? 1900 : (DCB(nvrram[RTC_CENTURY]) * 100);
}
void time_internal_sync(char *nvrram)
{
struct tm *cur_time_tm;
time_t cur_time;
time(&cur_time);
cur_time_tm = localtime(&cur_time);
time_internal_set(cur_time_tm);
time_set_nvrram(nvrram, cur_time_tm);
}
void time_get(char *nvrram)
{
struct tm cur_time_tm;
time_internal_get(&cur_time_tm);
time_set_nvrram(nvrram, &cur_time_tm);
}

View file

@ -170,3 +170,5 @@ enum RTC_RD_BITS
void rtc_tick(); void rtc_tick();
void time_update(char *nvrram, int reg); void time_update(char *nvrram, int reg);
void time_get(char *nvrram); void time_get(char *nvrram);
void time_internal_set_nvrram(char *nvrram);
void time_internal_sync(char *nvrram);