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).
This commit is contained in:
Mark Pizzolato 2016-12-09 18:01:21 -08:00
parent c393675b5b
commit 1c3c50fd26
4 changed files with 169 additions and 37 deletions

View file

@ -182,6 +182,7 @@ int32 tmr_poll = CLK_DELAY; /* pgm timer poll */
struct todr_battery_info { struct todr_battery_info {
uint32 toy_gmtbase; /* GMT base of set value */ uint32 toy_gmtbase; /* GMT base of set value */
uint32 toy_gmtbasemsec; /* The milliseconds of the 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; typedef struct todr_battery_info TOY;
@ -534,7 +535,7 @@ t_stat tti_svc (UNIT *uptr)
{ {
int32 c; 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? */ if ((tti_csr & CSR_DONE) && /* input still pending and < 500ms? */
((sim_os_msec () - tti_buftime) < 500)) ((sim_os_msec () - tti_buftime) < 500))
@ -842,6 +843,20 @@ const char *clk_description (DEVICE *dptr)
return "time of year clock"; 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 */ /* CLK attach */
t_stat clk_attach (UNIT *uptr, CONST char *cptr) 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); r = attach_unit (uptr, cptr);
if (r != SCPE_OK) if (r != SCPE_OK)
uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE); uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE);
else else {
TOY *toy = (TOY *)uptr->filebuf;
uptr->hwmark = (uint32) uptr->capac; 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; return r;
} }
@ -897,10 +925,18 @@ int32 todr_rd (void)
TOY *toy = (TOY *)clk_unit.filebuf; TOY *toy = (TOY *)clk_unit.filebuf;
struct timespec base, now, val; 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 */ sim_rtcn_get_time(&now, TMR_CLK); /* get curr time */
base.tv_sec = toy->toy_gmtbase; base.tv_sec = toy->toy_gmtbase;
base.tv_nsec = toy->toy_gmtbasemsec * 1000000; base.tv_nsec = toy->toy_gmtbasemsec * 1000000;
sim_timespec_diff (&val, &now, &base); 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 */ return (int32)(val.tv_sec*100 + val.tv_nsec/10000000); /* 100hz Clock Ticks */
} }
@ -910,8 +946,9 @@ void todr_wr (int32 data)
TOY *toy = (TOY *)clk_unit.filebuf; TOY *toy = (TOY *)clk_unit.filebuf;
struct timespec now, val, base; struct timespec now, val, base;
/* Save the GMT time when set value was 0 to record the base for future if (data) {
read operations in "battery backed-up" state */ /* 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 */ sim_rtcn_get_time(&now, TMR_CLK); /* get curr time */
val.tv_sec = ((uint32)data) / 100; val.tv_sec = ((uint32)data) / 100;
@ -920,6 +957,11 @@ sim_timespec_diff (&base, &now, &val); /* base = now - data */
toy->toy_gmtbase = (uint32)base.tv_sec; toy->toy_gmtbase = (uint32)base.tv_sec;
toy->toy_gmtbasemsec = base.tv_nsec/1000000; toy->toy_gmtbasemsec = base.tv_nsec/1000000;
} }
else { /* stop the clock */
toy->toy_gmtbase = 0;
toy->toy_gmtbasemsec = 0;
}
}
t_stat todr_resync (void) t_stat todr_resync (void)
{ {

View file

@ -213,6 +213,7 @@ int32 tmr_poll = CLK_DELAY; /* pgm timer poll */
struct todr_battery_info { struct todr_battery_info {
uint32 toy_gmtbase; /* GMT base of set value */ uint32 toy_gmtbase; /* GMT base of set value */
uint32 toy_gmtbasemsec; /* The milliseconds of the 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; typedef struct todr_battery_info TOY;
@ -502,7 +503,7 @@ t_stat tti_svc (UNIT *uptr)
{ {
int32 c; 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? */ if ((tti_csr & CSR_DONE) && /* input still pending and < 500ms? */
((sim_os_msec () - tti_buftime) < 500)) ((sim_os_msec () - tti_buftime) < 500))
@ -784,6 +785,20 @@ const char *clk_description (DEVICE *dptr)
return "time of year clock"; 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 */ /* CLK attach */
t_stat clk_attach (UNIT *uptr, CONST char *cptr) 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); r = attach_unit (uptr, cptr);
if (r != SCPE_OK) if (r != SCPE_OK)
uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE); uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE);
else else {
TOY *toy = (TOY *)uptr->filebuf;
uptr->hwmark = (uint32) uptr->capac; 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; return r;
} }
@ -850,8 +878,8 @@ void todr_wr (int32 data)
TOY *toy = (TOY *)clk_unit.filebuf; TOY *toy = (TOY *)clk_unit.filebuf;
struct timespec now, val, base; struct timespec now, val, base;
/* Save the GMT time when set value was 0 to record the base for future /* Save the GMT time when set value was written to record the base for
read operations in "battery backed-up" state */ future read operations in "battery backed-up" state */
sim_rtcn_get_time(&now, TMR_CLK); /* get curr time */ sim_rtcn_get_time(&now, TMR_CLK); /* get curr time */
val.tv_sec = ((uint32)data) / 100; val.tv_sec = ((uint32)data) / 100;

View file

@ -212,6 +212,7 @@ int32 tmr_poll = CLK_DELAY; /* pgm timer poll */
struct todr_battery_info { struct todr_battery_info {
uint32 toy_gmtbase; /* GMT base of set value */ uint32 toy_gmtbase; /* GMT base of set value */
uint32 toy_gmtbasemsec; /* The milliseconds of the 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; typedef struct todr_battery_info TOY;
@ -590,7 +591,7 @@ int32 line = uptr - tti_dev.units;
switch (line) { switch (line) {
case ID_CT: /* console terminal */ 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? */ if ((tti_csr & CSR_DONE) && /* input still pending and < 500ms? */
((sim_os_msec () - tti_buftime) < 500)) ((sim_os_msec () - tti_buftime) < 500))
return SCPE_OK; return SCPE_OK;
@ -910,6 +911,20 @@ const char *clk_description (DEVICE *dptr)
return "time of year clock"; 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 */ /* CLK attach */
t_stat clk_attach (UNIT *uptr, CONST char *cptr) 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); r = attach_unit (uptr, cptr);
if (r != SCPE_OK) if (r != SCPE_OK)
uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE); uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE);
else else {
TOY *toy = (TOY *)uptr->filebuf;
uptr->hwmark = (uint32) uptr->capac; 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; return r;
} }
@ -976,8 +1004,8 @@ void todr_wr (int32 data)
TOY *toy = (TOY *)clk_unit.filebuf; TOY *toy = (TOY *)clk_unit.filebuf;
struct timespec now, val, base; struct timespec now, val, base;
/* Save the GMT time when set value was 0 to record the base for future /* Save the GMT time when set value was 0 to record the base for
read operations in "battery backed-up" state */ future read operations in "battery backed-up" state */
sim_rtcn_get_time(&now, TMR_CLK); /* get curr time */ sim_rtcn_get_time(&now, TMR_CLK); /* get curr time */
val.tv_sec = ((uint32)data) / 100; val.tv_sec = ((uint32)data) / 100;

View file

@ -103,6 +103,7 @@ int32 todr_blow = 1; /* TODR battery low */
struct todr_battery_info { struct todr_battery_info {
uint32 toy_gmtbase; /* GMT base of set value */ uint32 toy_gmtbase; /* GMT base of set value */
uint32 toy_gmtbasemsec; /* The milliseconds of the 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; typedef struct todr_battery_info TOY;
int32 tmxr_poll = CLK_DELAY * TMXR_MULT; /* term mux poll */ int32 tmxr_poll = CLK_DELAY * TMXR_MULT; /* term mux poll */
@ -344,7 +345,7 @@ t_stat tti_svc (UNIT *uptr)
{ {
int32 c; 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? */ if ((tti_csr & CSR_DONE) && /* input still pending and < 500ms? */
((sim_os_msec () - tti_buftime) < 500)) ((sim_os_msec () - tti_buftime) < 500))
@ -464,6 +465,7 @@ tmr_poll = t; /* set tmr poll */
tmxr_poll = t * TMXR_MULT; /* set mux poll */ tmxr_poll = t * TMXR_MULT; /* set mux poll */
if (!todr_blow && todr_reg) /* if running? */ if (!todr_blow && todr_reg) /* if running? */
todr_reg = todr_reg + 1; /* incr TODR */ todr_reg = todr_reg + 1; /* incr TODR */
AIO_SET_INTERRUPT_LATENCY(tmr_poll*clk_tps); /* set interrrupt latency */
return SCPE_OK; return SCPE_OK;
} }
@ -506,8 +508,10 @@ void todr_wr (int32 data)
TOY *toy = (TOY *)clk_unit.filebuf; TOY *toy = (TOY *)clk_unit.filebuf;
struct timespec now, val, base; struct timespec now, val, base;
/* Save the GMT time when set value was 0 to record the base for future if (data) {
read operations in "battery backed-up" state */ 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 */ sim_rtcn_get_time(&now, TMR_CLK); /* get curr time */
val.tv_sec = ((uint32)data) / 100; val.tv_sec = ((uint32)data) / 100;
@ -515,9 +519,12 @@ val.tv_nsec = (((uint32)data) % 100) * 10000000;
sim_timespec_diff (&base, &now, &val); /* base = now - data */ sim_timespec_diff (&base, &now, &val); /* base = now - data */
toy->toy_gmtbase = (uint32)base.tv_sec; toy->toy_gmtbase = (uint32)base.tv_sec;
toy->toy_gmtbasemsec = base.tv_nsec/1000000; toy->toy_gmtbasemsec = base.tv_nsec/1000000;
}
else { /* stop the clock */
toy->toy_gmtbase = 0;
toy->toy_gmtbasemsec = 0;
}
todr_reg = data; todr_reg = data;
if (data)
todr_blow = 0;
sim_debug (DBG_REG, &clk_dev, "todr_wr(0x%X) - TODR=0x%X blow=%d\n", data, todr_reg, todr_blow); sim_debug (DBG_REG, &clk_dev, "todr_wr(0x%X) - TODR=0x%X blow=%d\n", data, todr_reg, todr_blow);
} }
@ -610,6 +617,20 @@ const char *clk_description (DEVICE *dptr)
return "time of year clock"; 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 */ /* CLK attach */
t_stat clk_attach (UNIT *uptr, CONST char *cptr) 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); r = attach_unit (uptr, cptr);
if (r != SCPE_OK) if (r != SCPE_OK)
uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE); uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE);
else else {
TOY *toy = (TOY *)uptr->filebuf;
uptr->hwmark = (uint32) uptr->capac; 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; return r;
} }