From 1c3c50fd2622b2414e561c03ea5b9d946e6ee5a9 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Fri, 9 Dec 2016 18:01:21 -0800 Subject: [PATCH] VAX, VAX780, VAX750, VAX8600: Make TODR state file endian independent When the TODR device (CLK) is attached to a state file, it operates in OS agnostic mode. This file can now be ported between hosts with different endianness and work consistently to track the time of year. Additionally, the VAX and VAX750 TODR values now properly don't progress when they have zero values (or when they overflow back to zero). --- VAX/vax750_stddev.c | 62 +++++++++++++++++++++++++++++++++++------- VAX/vax780_stddev.c | 42 ++++++++++++++++++++++++----- VAX/vax860_stddev.c | 36 ++++++++++++++++++++++--- VAX/vax_stddev.c | 66 ++++++++++++++++++++++++++++++++++----------- 4 files changed, 169 insertions(+), 37 deletions(-) diff --git a/VAX/vax750_stddev.c b/VAX/vax750_stddev.c index 9e62811c..78355848 100644 --- a/VAX/vax750_stddev.c +++ b/VAX/vax750_stddev.c @@ -182,6 +182,7 @@ int32 tmr_poll = CLK_DELAY; /* pgm timer poll */ struct todr_battery_info { uint32 toy_gmtbase; /* GMT base of set value */ uint32 toy_gmtbasemsec; /* The milliseconds of the set value */ + uint32 toy_endian_plus2; /* 2 -> Big Endian, 3 -> Little Endian, invalid otherwise */ }; typedef struct todr_battery_info TOY; @@ -534,7 +535,7 @@ t_stat tti_svc (UNIT *uptr) { int32 c; -sim_clock_coschedule (uptr, tmxr_poll); /* continue poll */ +sim_clock_coschedule_tmr (uptr, TMR_CLK, tmxr_poll); /* continue poll */ if ((tti_csr & CSR_DONE) && /* input still pending and < 500ms? */ ((sim_os_msec () - tti_buftime) < 500)) @@ -842,6 +843,20 @@ const char *clk_description (DEVICE *dptr) return "time of year clock"; } +static uint32 sim_byteswap32 (uint32 data) +{ +uint8 *bdata = (uint8 *)&data; +uint8 tmp; + +tmp = bdata[0]; +bdata[0] = bdata[3]; +bdata[3] = tmp; +tmp = bdata[1]; +bdata[1] = bdata[2]; +bdata[2] = tmp; +return data; +} + /* CLK attach */ t_stat clk_attach (UNIT *uptr, CONST char *cptr) @@ -853,8 +868,21 @@ memset (uptr->filebuf, 0, (size_t)uptr->capac); r = attach_unit (uptr, cptr); if (r != SCPE_OK) uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE); -else +else { + TOY *toy = (TOY *)uptr->filebuf; + uptr->hwmark = (uint32) uptr->capac; + if ((toy->toy_endian_plus2 < 2) || (toy->toy_endian_plus2 > 3)) + memset (uptr->filebuf, 0, (size_t)uptr->capac); + else { + if (toy->toy_endian_plus2 != sim_end + 2) { /* wrong endian? */ + toy->toy_gmtbase = sim_byteswap32 (toy->toy_gmtbase); + toy->toy_gmtbasemsec = sim_byteswap32 (toy->toy_gmtbasemsec); + } + } + toy->toy_endian_plus2 = sim_end + 2; + todr_resync (); + } return r; } @@ -897,10 +925,18 @@ int32 todr_rd (void) TOY *toy = (TOY *)clk_unit.filebuf; struct timespec base, now, val; +/* Maximum number of seconds which can be represented as 10ms ticks + in the 32bit TODR. This is the 33bit value 0x100000000/100 to get seconds */ +#define TOY_MAX_SECS (0x40000000/25) + sim_rtcn_get_time(&now, TMR_CLK); /* get curr time */ base.tv_sec = toy->toy_gmtbase; base.tv_nsec = toy->toy_gmtbasemsec * 1000000; sim_timespec_diff (&val, &now, &base); + +if ((val.tv_sec >= TOY_MAX_SECS) || (!toy->toy_gmtbase))/* todr overflowed? */ + return 0; /* stop counting */ + return (int32)(val.tv_sec*100 + val.tv_nsec/10000000); /* 100hz Clock Ticks */ } @@ -910,15 +946,21 @@ void todr_wr (int32 data) TOY *toy = (TOY *)clk_unit.filebuf; struct timespec now, val, base; -/* Save the GMT time when set value was 0 to record the base for future - read operations in "battery backed-up" state */ +if (data) { + /* Save the GMT time when set value was not 0 to record the base for + future read operations in "battery backed-up" state */ -sim_rtcn_get_time(&now, TMR_CLK); /* get curr time */ -val.tv_sec = ((uint32)data) / 100; -val.tv_nsec = (((uint32)data) % 100) * 10000000; -sim_timespec_diff (&base, &now, &val); /* base = now - data */ -toy->toy_gmtbase = (uint32)base.tv_sec; -toy->toy_gmtbasemsec = base.tv_nsec/1000000; + sim_rtcn_get_time(&now, TMR_CLK); /* get curr time */ + val.tv_sec = ((uint32)data) / 100; + val.tv_nsec = (((uint32)data) % 100) * 10000000; + sim_timespec_diff (&base, &now, &val); /* base = now - data */ + toy->toy_gmtbase = (uint32)base.tv_sec; + toy->toy_gmtbasemsec = base.tv_nsec/1000000; + } +else { /* stop the clock */ + toy->toy_gmtbase = 0; + toy->toy_gmtbasemsec = 0; + } } t_stat todr_resync (void) diff --git a/VAX/vax780_stddev.c b/VAX/vax780_stddev.c index a6bf3738..68c3b707 100644 --- a/VAX/vax780_stddev.c +++ b/VAX/vax780_stddev.c @@ -213,6 +213,7 @@ int32 tmr_poll = CLK_DELAY; /* pgm timer poll */ struct todr_battery_info { uint32 toy_gmtbase; /* GMT base of set value */ uint32 toy_gmtbasemsec; /* The milliseconds of the set value */ + uint32 toy_endian_plus2; /* 2 -> Big Endian, 3 -> Little Endian, invalid otherwise */ }; typedef struct todr_battery_info TOY; @@ -502,7 +503,7 @@ t_stat tti_svc (UNIT *uptr) { int32 c; -sim_clock_coschedule (uptr, tmxr_poll); /* continue poll */ +sim_clock_coschedule_tmr (uptr, TMR_CLK, tmxr_poll); /* continue poll */ if ((tti_csr & CSR_DONE) && /* input still pending and < 500ms? */ ((sim_os_msec () - tti_buftime) < 500)) @@ -784,6 +785,20 @@ const char *clk_description (DEVICE *dptr) return "time of year clock"; } +static uint32 sim_byteswap32 (uint32 data) +{ +uint8 *bdata = (uint8 *)&data; +uint8 tmp; + +tmp = bdata[0]; +bdata[0] = bdata[3]; +bdata[3] = tmp; +tmp = bdata[1]; +bdata[1] = bdata[2]; +bdata[2] = tmp; +return data; +} + /* CLK attach */ t_stat clk_attach (UNIT *uptr, CONST char *cptr) @@ -795,8 +810,21 @@ memset (uptr->filebuf, 0, (size_t)uptr->capac); r = attach_unit (uptr, cptr); if (r != SCPE_OK) uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE); -else +else { + TOY *toy = (TOY *)uptr->filebuf; + uptr->hwmark = (uint32) uptr->capac; + if ((toy->toy_endian_plus2 < 2) || (toy->toy_endian_plus2 > 3)) + memset (uptr->filebuf, 0, (size_t)uptr->capac); + else { + if (toy->toy_endian_plus2 != sim_end + 2) { /* wrong endian? */ + toy->toy_gmtbase = sim_byteswap32 (toy->toy_gmtbase); + toy->toy_gmtbasemsec = sim_byteswap32 (toy->toy_gmtbasemsec); + } + } + toy->toy_endian_plus2 = sim_end + 2; + todr_resync (); + } return r; } @@ -850,8 +878,8 @@ void todr_wr (int32 data) TOY *toy = (TOY *)clk_unit.filebuf; struct timespec now, val, base; -/* Save the GMT time when set value was 0 to record the base for future - read operations in "battery backed-up" state */ +/* Save the GMT time when set value was written to record the base for + future read operations in "battery backed-up" state */ sim_rtcn_get_time(&now, TMR_CLK); /* get curr time */ val.tv_sec = ((uint32)data) / 100; @@ -881,9 +909,9 @@ else { /* Not-Attached means */ if (ctm == NULL) /* error? */ return SCPE_NOFNC; base = (((((ctm->tm_yday * 24) + /* sec since 1-Jan */ - ctm->tm_hour) * 60) + - ctm->tm_min) * 60) + - ctm->tm_sec; + ctm->tm_hour) * 60) + + ctm->tm_min) * 60) + + ctm->tm_sec; todr_wr ((base * 100) + 0x10000000); /* use VMS form */ } return SCPE_OK; diff --git a/VAX/vax860_stddev.c b/VAX/vax860_stddev.c index 4178f036..b3396932 100644 --- a/VAX/vax860_stddev.c +++ b/VAX/vax860_stddev.c @@ -212,6 +212,7 @@ int32 tmr_poll = CLK_DELAY; /* pgm timer poll */ struct todr_battery_info { uint32 toy_gmtbase; /* GMT base of set value */ uint32 toy_gmtbasemsec; /* The milliseconds of the set value */ + uint32 toy_endian_plus2; /* 2 -> Big Endian, 3 -> Little Endian, invalid otherwise */ }; typedef struct todr_battery_info TOY; @@ -590,7 +591,7 @@ int32 line = uptr - tti_dev.units; switch (line) { case ID_CT: /* console terminal */ - sim_clock_coschedule (uptr, tmxr_poll); /* continue poll */ + sim_clock_coschedule_tmr (uptr, TMR_CLK, tmxr_poll);/* continue poll */ if ((tti_csr & CSR_DONE) && /* input still pending and < 500ms? */ ((sim_os_msec () - tti_buftime) < 500)) return SCPE_OK; @@ -910,6 +911,20 @@ const char *clk_description (DEVICE *dptr) return "time of year clock"; } +static uint32 sim_byteswap32 (uint32 data) +{ +uint8 *bdata = (uint8 *)&data; +uint8 tmp; + +tmp = bdata[0]; +bdata[0] = bdata[3]; +bdata[3] = tmp; +tmp = bdata[1]; +bdata[1] = bdata[2]; +bdata[2] = tmp; +return data; +} + /* CLK attach */ t_stat clk_attach (UNIT *uptr, CONST char *cptr) @@ -921,8 +936,21 @@ memset (uptr->filebuf, 0, (size_t)uptr->capac); r = attach_unit (uptr, cptr); if (r != SCPE_OK) uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE); -else +else { + TOY *toy = (TOY *)uptr->filebuf; + uptr->hwmark = (uint32) uptr->capac; + if ((toy->toy_endian_plus2 < 2) || (toy->toy_endian_plus2 > 3)) + memset (uptr->filebuf, 0, (size_t)uptr->capac); + else { + if (toy->toy_endian_plus2 != sim_end + 2) { /* wrong endian? */ + toy->toy_gmtbase = sim_byteswap32 (toy->toy_gmtbase); + toy->toy_gmtbasemsec = sim_byteswap32 (toy->toy_gmtbasemsec); + } + } + toy->toy_endian_plus2 = sim_end + 2; + todr_resync (); + } return r; } @@ -976,8 +1004,8 @@ void todr_wr (int32 data) TOY *toy = (TOY *)clk_unit.filebuf; struct timespec now, val, base; -/* Save the GMT time when set value was 0 to record the base for future - read operations in "battery backed-up" state */ +/* Save the GMT time when set value was 0 to record the base for + future read operations in "battery backed-up" state */ sim_rtcn_get_time(&now, TMR_CLK); /* get curr time */ val.tv_sec = ((uint32)data) / 100; diff --git a/VAX/vax_stddev.c b/VAX/vax_stddev.c index eb124cc3..abfc8f72 100644 --- a/VAX/vax_stddev.c +++ b/VAX/vax_stddev.c @@ -103,6 +103,7 @@ int32 todr_blow = 1; /* TODR battery low */ struct todr_battery_info { uint32 toy_gmtbase; /* GMT base of set value */ uint32 toy_gmtbasemsec; /* The milliseconds of the set value */ + uint32 toy_endian_plus2; /* 2 -> Big Endian, 3 -> Little Endian, invalid otherwise */ }; typedef struct todr_battery_info TOY; int32 tmxr_poll = CLK_DELAY * TMXR_MULT; /* term mux poll */ @@ -344,7 +345,7 @@ t_stat tti_svc (UNIT *uptr) { int32 c; -sim_clock_coschedule (uptr, tmxr_poll); /* continue poll */ +sim_clock_coschedule_tmr (uptr, TMR_CLK, tmxr_poll); /* continue poll */ if ((tti_csr & CSR_DONE) && /* input still pending and < 500ms? */ ((sim_os_msec () - tti_buftime) < 500)) @@ -464,6 +465,7 @@ tmr_poll = t; /* set tmr poll */ tmxr_poll = t * TMXR_MULT; /* set mux poll */ if (!todr_blow && todr_reg) /* if running? */ todr_reg = todr_reg + 1; /* incr TODR */ +AIO_SET_INTERRUPT_LATENCY(tmr_poll*clk_tps); /* set interrrupt latency */ return SCPE_OK; } @@ -506,18 +508,23 @@ void todr_wr (int32 data) TOY *toy = (TOY *)clk_unit.filebuf; struct timespec now, val, base; -/* Save the GMT time when set value was 0 to record the base for future - read operations in "battery backed-up" state */ - -sim_rtcn_get_time(&now, TMR_CLK); /* get curr time */ -val.tv_sec = ((uint32)data) / 100; -val.tv_nsec = (((uint32)data) % 100) * 10000000; -sim_timespec_diff (&base, &now, &val); /* base = now - data */ -toy->toy_gmtbase = (uint32)base.tv_sec; -toy->toy_gmtbasemsec = base.tv_nsec/1000000; -todr_reg = data; -if (data) +if (data) { todr_blow = 0; + /* Save the GMT time when set value is not 0 to record the base for + future read operations in "battery backed-up" state */ + + sim_rtcn_get_time(&now, TMR_CLK); /* get curr time */ + val.tv_sec = ((uint32)data) / 100; + val.tv_nsec = (((uint32)data) % 100) * 10000000; + sim_timespec_diff (&base, &now, &val); /* base = now - data */ + toy->toy_gmtbase = (uint32)base.tv_sec; + toy->toy_gmtbasemsec = base.tv_nsec/1000000; + } +else { /* stop the clock */ + toy->toy_gmtbase = 0; + toy->toy_gmtbasemsec = 0; + } +todr_reg = data; sim_debug (DBG_REG, &clk_dev, "todr_wr(0x%X) - TODR=0x%X blow=%d\n", data, todr_reg, todr_blow); } @@ -543,9 +550,9 @@ else { /* Not-Attached means */ if (ctm == NULL) /* error? */ return SCPE_NOFNC; base = (((((ctm->tm_yday * 24) + /* sec since 1-Jan */ - ctm->tm_hour) * 60) + - ctm->tm_min) * 60) + - ctm->tm_sec; + ctm->tm_hour) * 60) + + ctm->tm_min) * 60) + + ctm->tm_sec; todr_wr ((base * 100) + 0x10000000); /* use VMS form */ } return SCPE_OK; @@ -610,6 +617,20 @@ const char *clk_description (DEVICE *dptr) return "time of year clock"; } +static uint32 sim_byteswap32 (uint32 data) +{ +uint8 *bdata = (uint8 *)&data; +uint8 tmp; + +tmp = bdata[0]; +bdata[0] = bdata[3]; +bdata[3] = tmp; +tmp = bdata[1]; +bdata[1] = bdata[2]; +bdata[2] = tmp; +return data; +} + /* CLK attach */ t_stat clk_attach (UNIT *uptr, CONST char *cptr) @@ -621,8 +642,21 @@ memset (uptr->filebuf, 0, (size_t)uptr->capac); r = attach_unit (uptr, cptr); if (r != SCPE_OK) uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE); -else +else { + TOY *toy = (TOY *)uptr->filebuf; + uptr->hwmark = (uint32) uptr->capac; + if ((toy->toy_endian_plus2 < 2) || (toy->toy_endian_plus2 > 3)) + memset (uptr->filebuf, 0, (size_t)uptr->capac); + else { + if (toy->toy_endian_plus2 != sim_end + 2) { /* wrong endian? */ + toy->toy_gmtbase = sim_byteswap32 (toy->toy_gmtbase); + toy->toy_gmtbasemsec = sim_byteswap32 (toy->toy_gmtbasemsec); + } + } + toy->toy_endian_plus2 = sim_end + 2; + todr_resync (); + } return r; }