Merge branch 'VAX-TODR'
This commit is contained in:
commit
7f9a612e96
4 changed files with 314 additions and 66 deletions
|
@ -29,6 +29,30 @@
|
||||||
todr TODR clock
|
todr TODR clock
|
||||||
tmr interval timer
|
tmr interval timer
|
||||||
|
|
||||||
|
28-Sep-11 MP Generalized setting TODR for all OSes.
|
||||||
|
Unbound the TODR value from the 100hz clock tick
|
||||||
|
interrupt. TODR now behaves like the original
|
||||||
|
battery backed-up clock and runs with the wall
|
||||||
|
clock, not the simulated instruction clock.
|
||||||
|
Two operational modes are available:
|
||||||
|
- Default VMS mode, which is similar to the previous
|
||||||
|
behavior in that without initializing the TODR it
|
||||||
|
would default to the value VMS would set it to if
|
||||||
|
VMS knew the correct time. This would be correct
|
||||||
|
almost all the time unless a VMS disk hadn't been
|
||||||
|
booted from for more than a year. This mode
|
||||||
|
produces strange time results for non VMS OSes on
|
||||||
|
each system boot.
|
||||||
|
- OS Agnostic mode. This mode behaves precisely like
|
||||||
|
the VAX780 TODR and works correctly for all OSes.
|
||||||
|
This mode is enabled by attaching the TODR to a
|
||||||
|
battery backup state file for the TOY clock
|
||||||
|
(i.e. sim> attach TODR TOY_CLOCK). When operating
|
||||||
|
in OS Agnostic mode, the TODR will initially start
|
||||||
|
counting from 0 and be adjusted differently when an
|
||||||
|
OS specifically writes to the TODR. VMS will prompt
|
||||||
|
to set the time on each boot unless the SYSGEN
|
||||||
|
parameter TIMEPROMPTWAIT is set to 0.
|
||||||
21-Mar-11 RMS Added reboot capability
|
21-Mar-11 RMS Added reboot capability
|
||||||
17-Aug-08 RMS Resync TODR on any clock reset
|
17-Aug-08 RMS Resync TODR on any clock reset
|
||||||
18-Jun-07 RMS Added UNIT_IDLE flag to console input, clock
|
18-Jun-07 RMS Added UNIT_IDLE flag to console input, clock
|
||||||
|
@ -56,7 +80,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "vax_defs.h"
|
#include "vax_defs.h"
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
/* Terminal definitions */
|
/* Terminal definitions */
|
||||||
|
|
||||||
|
@ -171,6 +195,11 @@ int32 clk_tps = 100; /* ticks/second */
|
||||||
int32 tmxr_poll = CLK_DELAY * TMXR_MULT; /* term mux poll */
|
int32 tmxr_poll = CLK_DELAY * TMXR_MULT; /* term mux poll */
|
||||||
int32 tmr_poll = CLK_DELAY; /* pgm timer poll */
|
int32 tmr_poll = CLK_DELAY; /* pgm timer poll */
|
||||||
int32 todr_reg = 0; /* TODR register */
|
int32 todr_reg = 0; /* TODR register */
|
||||||
|
struct todr_battery_info {
|
||||||
|
uint32 toy_gmtbase; /* GMT base of set value */
|
||||||
|
uint32 toy_gmtbasemsec; /* The milliseconds of the set value */
|
||||||
|
};
|
||||||
|
typedef struct todr_battery_info TOY;
|
||||||
|
|
||||||
int32 fl_fnc = 0; /* function */
|
int32 fl_fnc = 0; /* function */
|
||||||
int32 fl_esr = 0; /* error status */
|
int32 fl_esr = 0; /* error status */
|
||||||
|
@ -197,6 +226,8 @@ t_stat tmr_svc (UNIT *uptr);
|
||||||
t_stat tti_reset (DEVICE *dptr);
|
t_stat tti_reset (DEVICE *dptr);
|
||||||
t_stat tto_reset (DEVICE *dptr);
|
t_stat tto_reset (DEVICE *dptr);
|
||||||
t_stat clk_reset (DEVICE *dptr);
|
t_stat clk_reset (DEVICE *dptr);
|
||||||
|
t_stat clk_attach (UNIT *uptr, char *cptr);
|
||||||
|
t_stat clk_detach (UNIT *uptr);
|
||||||
t_stat tmr_reset (DEVICE *dptr);
|
t_stat tmr_reset (DEVICE *dptr);
|
||||||
t_stat fl_svc (UNIT *uptr);
|
t_stat fl_svc (UNIT *uptr);
|
||||||
t_stat fl_reset (DEVICE *dptr);
|
t_stat fl_reset (DEVICE *dptr);
|
||||||
|
@ -281,7 +312,7 @@ DEVICE tto_dev = {
|
||||||
|
|
||||||
/* TODR and TMR data structures */
|
/* TODR and TMR data structures */
|
||||||
|
|
||||||
UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE, 0), CLK_DELAY }; /* 100Hz */
|
UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE+UNIT_FIX, sizeof(TOY)), CLK_DELAY };/* 100Hz */
|
||||||
|
|
||||||
REG clk_reg[] = {
|
REG clk_reg[] = {
|
||||||
{ DRDATA (TODR, todr_reg, 32), PV_LEFT },
|
{ DRDATA (TODR, todr_reg, 32), PV_LEFT },
|
||||||
|
@ -296,9 +327,9 @@ REG clk_reg[] = {
|
||||||
|
|
||||||
DEVICE clk_dev = {
|
DEVICE clk_dev = {
|
||||||
"TODR", &clk_unit, clk_reg, NULL,
|
"TODR", &clk_unit, clk_reg, NULL,
|
||||||
1, 0, 0, 0, 0, 0,
|
1, 0, 8, 1, 0, 0,
|
||||||
NULL, NULL, &clk_reset,
|
NULL, NULL, &clk_reset,
|
||||||
NULL, NULL, NULL,
|
NULL, &clk_attach, &clk_detach,
|
||||||
NULL, 0
|
NULL, 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -578,7 +609,6 @@ tmr_poll = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */
|
||||||
sim_activate (&clk_unit, tmr_poll); /* reactivate unit */
|
sim_activate (&clk_unit, tmr_poll); /* reactivate unit */
|
||||||
tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */
|
tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */
|
||||||
AIO_SET_INTERRUPT_LATENCY(tmr_poll*clk_tps); /* set interrrupt latency */
|
AIO_SET_INTERRUPT_LATENCY(tmr_poll*clk_tps); /* set interrrupt latency */
|
||||||
todr_reg = todr_reg + 1; /* incr TODR */
|
|
||||||
if ((tmr_iccs & TMR_CSR_RUN) && tmr_use_100hz) /* timer on, std intvl? */
|
if ((tmr_iccs & TMR_CSR_RUN) && tmr_use_100hz) /* timer on, std intvl? */
|
||||||
tmr_incr (TMR_INC); /* do timer service */
|
tmr_incr (TMR_INC); /* do timer service */
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
|
@ -651,9 +681,44 @@ t_stat clk_reset (DEVICE *dptr)
|
||||||
tmr_poll = sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init 100Hz timer */
|
tmr_poll = sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init 100Hz timer */
|
||||||
sim_activate_abs (&clk_unit, tmr_poll); /* activate 100Hz unit */
|
sim_activate_abs (&clk_unit, tmr_poll); /* activate 100Hz unit */
|
||||||
tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */
|
tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */
|
||||||
|
if (clk_unit.filebuf == NULL) { /* make sure the TODR is initialized */
|
||||||
|
clk_unit.filebuf = calloc(sizeof(TOY), 1);
|
||||||
|
if (clk_unit.filebuf == NULL)
|
||||||
|
return SCPE_MEM;
|
||||||
|
todr_resync ();
|
||||||
|
}
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* CLK attach */
|
||||||
|
|
||||||
|
t_stat clk_attach (UNIT *uptr, char *cptr)
|
||||||
|
{
|
||||||
|
t_stat r;
|
||||||
|
|
||||||
|
uptr->flags = uptr->flags | (UNIT_ATTABLE | UNIT_BUFABLE);
|
||||||
|
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
|
||||||
|
uptr->hwmark = (uint32) uptr->capac;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CLK detach */
|
||||||
|
|
||||||
|
t_stat clk_detach (UNIT *uptr)
|
||||||
|
{
|
||||||
|
t_stat r;
|
||||||
|
|
||||||
|
r = detach_unit (uptr);
|
||||||
|
if ((uptr->flags & UNIT_ATT) == 0)
|
||||||
|
uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Interval timer reset */
|
/* Interval timer reset */
|
||||||
|
|
||||||
t_stat tmr_reset (DEVICE *dptr)
|
t_stat tmr_reset (DEVICE *dptr)
|
||||||
|
@ -668,36 +733,89 @@ todr_resync (); /* resync TODR */
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
timeval_subtract (result, x, y)
|
||||||
|
struct timeval *result, *x, *y;
|
||||||
|
{
|
||||||
|
/* Perform the carry for the later subtraction by updating y. */
|
||||||
|
if (x->tv_usec < y->tv_usec) {
|
||||||
|
int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
|
||||||
|
y->tv_usec -= 1000000 * nsec;
|
||||||
|
y->tv_sec += nsec;
|
||||||
|
}
|
||||||
|
if (x->tv_usec - y->tv_usec > 1000000) {
|
||||||
|
int nsec = (x->tv_usec - y->tv_usec) / 1000000;
|
||||||
|
y->tv_usec += 1000000 * nsec;
|
||||||
|
y->tv_sec -= nsec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute the time remaining to wait.
|
||||||
|
tv_usec is certainly positive. */
|
||||||
|
result->tv_sec = x->tv_sec - y->tv_sec;
|
||||||
|
result->tv_usec = x->tv_usec - y->tv_usec;
|
||||||
|
|
||||||
|
/* Return 1 if result is negative. */
|
||||||
|
return x->tv_sec < y->tv_sec;
|
||||||
|
}
|
||||||
|
|
||||||
/* TODR routines */
|
/* TODR routines */
|
||||||
|
|
||||||
int32 todr_rd (void)
|
int32 todr_rd (void)
|
||||||
{
|
{
|
||||||
return todr_reg;
|
TOY *toy = (TOY *)clk_unit.filebuf;
|
||||||
|
struct timespec base, now, val;
|
||||||
|
|
||||||
|
clock_gettime(CLOCK_REALTIME, &now); /* get curr time */
|
||||||
|
base.tv_sec = toy->toy_gmtbase;
|
||||||
|
base.tv_nsec = toy->toy_gmtbasemsec * 1000000;
|
||||||
|
sim_timespec_diff (&val, &now, &base);
|
||||||
|
return (int32)(val.tv_sec*100 + val.tv_nsec/10000000); /* 100hz Clock Ticks */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void todr_wr (int32 data)
|
void todr_wr (int32 data)
|
||||||
{
|
{
|
||||||
todr_reg = data;
|
TOY *toy = (TOY *)clk_unit.filebuf;
|
||||||
return;
|
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 (-1 == clock_gettime(CLOCK_REALTIME, &now)) /* get curr time */
|
||||||
|
return; /* error? */
|
||||||
|
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 = base.tv_sec;
|
||||||
|
toy->toy_gmtbasemsec = base.tv_nsec/1000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
t_stat todr_resync (void)
|
t_stat todr_resync (void)
|
||||||
{
|
{
|
||||||
uint32 base;
|
TOY *toy = (TOY *)clk_unit.filebuf;
|
||||||
time_t curr;
|
|
||||||
struct tm *ctm;
|
|
||||||
|
|
||||||
curr = time (NULL); /* get curr time */
|
if (clk_unit.flags & UNIT_ATT) { /* Attached means behave like real VAX780 */
|
||||||
if (curr == (time_t) -1) /* error? */
|
if (!toy->toy_gmtbase) /* Never set? */
|
||||||
return SCPE_NOFNC;
|
todr_wr (0); /* Start ticking from 0 */
|
||||||
ctm = localtime (&curr); /* decompose */
|
}
|
||||||
if (ctm == NULL) /* error? */
|
else { /* Not-Attached means */
|
||||||
return SCPE_NOFNC;
|
uint32 base; /* behave like simh VMS default */
|
||||||
base = (((((ctm->tm_yday * 24) + /* sec since 1-Jan */
|
time_t curr;
|
||||||
ctm->tm_hour) * 60) +
|
struct tm *ctm;
|
||||||
ctm->tm_min) * 60) +
|
|
||||||
ctm->tm_sec;
|
curr = time (NULL); /* get curr time */
|
||||||
todr_reg = (base * 100) + 0x10000000; /* cvt to VAX form */
|
if (curr == (time_t) -1) /* error? */
|
||||||
|
return SCPE_NOFNC;
|
||||||
|
ctm = localtime (&curr); /* decompose */
|
||||||
|
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;
|
||||||
|
todr_wr ((base * 100) + 0x10000000); /* use VMS form */
|
||||||
|
}
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
179
VAX/vax_stddev.c
179
VAX/vax_stddev.c
|
@ -27,6 +27,31 @@
|
||||||
tto terminal output
|
tto terminal output
|
||||||
clk 100Hz and TODR clock
|
clk 100Hz and TODR clock
|
||||||
|
|
||||||
|
28-Sep-11 MP Generalized setting TODR for all OSes.
|
||||||
|
Unbound the TODR value from the 100hz clock tick
|
||||||
|
interrupt. TODR now behaves like the original
|
||||||
|
battery backed-up clock and runs with the wall
|
||||||
|
clock, not the simulated instruction clock
|
||||||
|
(except when running ROM diagnostics).
|
||||||
|
Two operational modes are available:
|
||||||
|
- Default VMS mode, which is similar to the previous
|
||||||
|
behavior in that without initializing the TODR it
|
||||||
|
would default to the value VMS would set it to if
|
||||||
|
VMS knew the correct time. This would be correct
|
||||||
|
almost all the time unless a VMS disk hadn't been
|
||||||
|
booted from for more than a year. This mode
|
||||||
|
produces strange time results for non VMS OSes on
|
||||||
|
each system boot.
|
||||||
|
- OS Agnostic mode. This mode behaves precisely like
|
||||||
|
the VAX780 TODR and works correctly for all OSes.
|
||||||
|
This mode is enabled by attaching the TODR to a
|
||||||
|
battery backup state file for the TOY clock
|
||||||
|
(i.e. sim> attach TODR TOY_CLOCK). When operating
|
||||||
|
in OS Agnostic mode, the TODR will initially start
|
||||||
|
counting from 0 and be adjusted differently when an
|
||||||
|
OS specifically writes to the TODR. VMS will prompt
|
||||||
|
to set the time on each boot unless the SYSGEN
|
||||||
|
parameter TIMEPROMPTWAIT is set to 0.
|
||||||
05-Jan-11 MP Added Asynch I/O support
|
05-Jan-11 MP Added Asynch I/O support
|
||||||
17-Aug-08 RMS Resync TODR on any clock reset
|
17-Aug-08 RMS Resync TODR on any clock reset
|
||||||
18-Jun-07 RMS Added UNIT_IDLE flag to console input, clock
|
18-Jun-07 RMS Added UNIT_IDLE flag to console input, clock
|
||||||
|
@ -70,6 +95,11 @@ int32 clk_csr = 0; /* control/status */
|
||||||
int32 clk_tps = 100; /* ticks/second */
|
int32 clk_tps = 100; /* ticks/second */
|
||||||
int32 todr_reg = 0; /* TODR register */
|
int32 todr_reg = 0; /* TODR register */
|
||||||
int32 todr_blow = 1; /* TODR battery low */
|
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 */
|
||||||
|
};
|
||||||
|
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 */
|
||||||
int32 tmr_poll = CLK_DELAY; /* pgm timer poll */
|
int32 tmr_poll = CLK_DELAY; /* pgm timer poll */
|
||||||
|
|
||||||
|
@ -79,9 +109,12 @@ t_stat clk_svc (UNIT *uptr);
|
||||||
t_stat tti_reset (DEVICE *dptr);
|
t_stat tti_reset (DEVICE *dptr);
|
||||||
t_stat tto_reset (DEVICE *dptr);
|
t_stat tto_reset (DEVICE *dptr);
|
||||||
t_stat clk_reset (DEVICE *dptr);
|
t_stat clk_reset (DEVICE *dptr);
|
||||||
|
t_stat clk_attach (UNIT *uptr, char *cptr);
|
||||||
|
t_stat clk_detach (UNIT *uptr);
|
||||||
t_stat todr_resync (void);
|
t_stat todr_resync (void);
|
||||||
|
|
||||||
extern int32 sysd_hlt_enb (void);
|
extern int32 sysd_hlt_enb (void);
|
||||||
|
extern int32 fault_PC;
|
||||||
|
|
||||||
/* TTI data structures
|
/* TTI data structures
|
||||||
|
|
||||||
|
@ -168,7 +201,7 @@ DEVICE tto_dev = {
|
||||||
|
|
||||||
DIB clk_dib = { 0, 0, NULL, NULL, 1, IVCL (CLK), SCB_INTTIM, { NULL } };
|
DIB clk_dib = { 0, 0, NULL, NULL, 1, IVCL (CLK), SCB_INTTIM, { NULL } };
|
||||||
|
|
||||||
UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE, 0), CLK_DELAY };
|
UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE+UNIT_FIX, sizeof(TOY)), CLK_DELAY };/* 100Hz */
|
||||||
|
|
||||||
REG clk_reg[] = {
|
REG clk_reg[] = {
|
||||||
{ HRDATA (CSR, clk_csr, 16) },
|
{ HRDATA (CSR, clk_csr, 16) },
|
||||||
|
@ -194,16 +227,15 @@ MTAB clk_mod[] = {
|
||||||
|
|
||||||
DEVICE clk_dev = {
|
DEVICE clk_dev = {
|
||||||
"CLK", &clk_unit, clk_reg, clk_mod,
|
"CLK", &clk_unit, clk_reg, clk_mod,
|
||||||
1, 0, 0, 0, 0, 0,
|
1, 0, 8, 1, 0, 0,
|
||||||
NULL, NULL, &clk_reset,
|
NULL, NULL, &clk_reset,
|
||||||
NULL, NULL, NULL,
|
NULL, &clk_attach, &clk_detach,
|
||||||
&clk_dib, 0
|
&clk_dib, 0
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Clock and terminal MxPR routines
|
/* Clock and terminal MxPR routines
|
||||||
|
|
||||||
iccs_rd/wr interval timer
|
iccs_rd/wr interval timer
|
||||||
todr_rd/wr time of year clock
|
|
||||||
rxcs_rd/wr input control/status
|
rxcs_rd/wr input control/status
|
||||||
rxdb_rd input buffer
|
rxdb_rd input buffer
|
||||||
txcs_rd/wr output control/status
|
txcs_rd/wr output control/status
|
||||||
|
@ -215,11 +247,6 @@ int32 iccs_rd (void)
|
||||||
return (clk_csr & CLKCSR_IMP);
|
return (clk_csr & CLKCSR_IMP);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 todr_rd (void)
|
|
||||||
{
|
|
||||||
return todr_reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 rxcs_rd (void)
|
int32 rxcs_rd (void)
|
||||||
{
|
{
|
||||||
return (tti_csr & TTICSR_IMP);
|
return (tti_csr & TTICSR_IMP);
|
||||||
|
@ -248,14 +275,6 @@ clk_csr = (clk_csr & ~CLKCSR_RW) | (data & CLKCSR_RW);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void todr_wr (int32 data)
|
|
||||||
{
|
|
||||||
todr_reg = data;
|
|
||||||
if (data)
|
|
||||||
todr_blow = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rxcs_wr (int32 data)
|
void rxcs_wr (int32 data)
|
||||||
{
|
{
|
||||||
if ((data & CSR_IE) == 0)
|
if ((data & CSR_IE) == 0)
|
||||||
|
@ -358,7 +377,8 @@ return SCPE_OK;
|
||||||
|
|
||||||
clk_svc process event (clock tick)
|
clk_svc process event (clock tick)
|
||||||
clk_reset process reset
|
clk_reset process reset
|
||||||
todr_powerup powerup for TODR (get date from system)
|
todr_rd/wr time of year clock
|
||||||
|
todr_resync powerup for TODR (get date from system)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
t_stat clk_svc (UNIT *uptr)
|
t_stat clk_svc (UNIT *uptr)
|
||||||
|
@ -371,8 +391,8 @@ t = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */
|
||||||
sim_activate (&clk_unit, t); /* reactivate unit */
|
sim_activate (&clk_unit, t); /* reactivate unit */
|
||||||
tmr_poll = t; /* set tmr poll */
|
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) /* incr TODR */
|
if (!todr_blow && todr_reg) /* if running? */
|
||||||
todr_reg = todr_reg + 1;
|
todr_reg = todr_reg + 1; /* incr TODR */
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,26 +406,80 @@ t = sim_is_active (&clk_unit);
|
||||||
return (t? t - 1: wait);
|
return (t? t - 1: wait);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32 todr_rd (void)
|
||||||
|
{
|
||||||
|
TOY *toy = (TOY *)clk_unit.filebuf;
|
||||||
|
struct timespec base, now, val;
|
||||||
|
|
||||||
|
if ((fault_PC&0xFFFE0000) == 0x20040000) /* running from ROM? */
|
||||||
|
return todr_reg; /* return counted value for ROM diags */
|
||||||
|
|
||||||
|
if (0 == todr_reg) /* clock running? */
|
||||||
|
return todr_reg;
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
|
||||||
|
clock_gettime(CLOCK_REALTIME, &now); /* 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) /* todr overflowed? */
|
||||||
|
return todr_reg = 0; /* stop counting */
|
||||||
|
|
||||||
|
return (int32)(val.tv_sec*100 + val.tv_nsec/10000000); /* 100hz Clock Ticks */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 (-1 == clock_gettime(CLOCK_REALTIME, &now)) /* get curr time */
|
||||||
|
return; /* error? */
|
||||||
|
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 = base.tv_sec;
|
||||||
|
toy->toy_gmtbasemsec = base.tv_nsec/1000000;
|
||||||
|
todr_reg = data;
|
||||||
|
if (data)
|
||||||
|
todr_blow = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* TODR resync routine */
|
/* TODR resync routine */
|
||||||
|
|
||||||
t_stat todr_resync (void)
|
t_stat todr_resync (void)
|
||||||
{
|
{
|
||||||
uint32 base;
|
TOY *toy = (TOY *)clk_unit.filebuf;
|
||||||
time_t curr;
|
|
||||||
struct tm *ctm;
|
|
||||||
|
|
||||||
curr = time (NULL); /* get curr time */
|
if (clk_unit.flags & UNIT_ATT) { /* Attached means behave like real VAX780 */
|
||||||
if (curr == (time_t) -1) /* error? */
|
if (!toy->toy_gmtbase) /* Never set? */
|
||||||
return SCPE_NOFNC;
|
todr_wr (0); /* Start ticking from 0 */
|
||||||
ctm = localtime (&curr); /* decompose */
|
}
|
||||||
if (ctm == NULL) /* error? */
|
else { /* Not-Attached means */
|
||||||
return SCPE_NOFNC;
|
uint32 base; /* behave like simh VMS default */
|
||||||
base = (((((ctm->tm_yday * 24) + /* sec since 1-Jan */
|
time_t curr;
|
||||||
ctm->tm_hour) * 60) +
|
struct tm *ctm;
|
||||||
ctm->tm_min) * 60) +
|
|
||||||
ctm->tm_sec;
|
curr = time (NULL); /* get curr time */
|
||||||
todr_reg = (base * 100) + 0x10000000; /* cvt to VAX form */
|
if (curr == (time_t) -1) /* error? */
|
||||||
todr_blow = 0;
|
return SCPE_NOFNC;
|
||||||
|
ctm = localtime (&curr); /* decompose */
|
||||||
|
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;
|
||||||
|
todr_wr ((base * 100) + 0x10000000); /* use VMS form */
|
||||||
|
}
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -415,13 +489,46 @@ t_stat clk_reset (DEVICE *dptr)
|
||||||
{
|
{
|
||||||
int32 t;
|
int32 t;
|
||||||
|
|
||||||
todr_resync (); /* resync clock */
|
|
||||||
clk_csr = 0;
|
clk_csr = 0;
|
||||||
CLR_INT (CLK);
|
CLR_INT (CLK);
|
||||||
t = sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init timer */
|
t = sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init timer */
|
||||||
sim_activate_abs (&clk_unit, t); /* activate unit */
|
sim_activate_abs (&clk_unit, t); /* activate unit */
|
||||||
tmr_poll = t; /* set tmr poll */
|
tmr_poll = t; /* set tmr poll */
|
||||||
tmxr_poll = t * TMXR_MULT; /* set mux poll */
|
tmxr_poll = t * TMXR_MULT; /* set mux poll */
|
||||||
|
if (clk_unit.filebuf == NULL) { /* make sure the TODR is initialized */
|
||||||
|
clk_unit.filebuf = calloc(sizeof(TOY), 1);
|
||||||
|
if (clk_unit.filebuf == NULL)
|
||||||
|
return SCPE_MEM;
|
||||||
|
todr_resync ();
|
||||||
|
}
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* CLK attach */
|
||||||
|
|
||||||
|
t_stat clk_attach (UNIT *uptr, char *cptr)
|
||||||
|
{
|
||||||
|
t_stat r;
|
||||||
|
|
||||||
|
uptr->flags = uptr->flags | (UNIT_ATTABLE | UNIT_BUFABLE);
|
||||||
|
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
|
||||||
|
uptr->hwmark = (uint32) uptr->capac;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CLK detach */
|
||||||
|
|
||||||
|
t_stat clk_detach (UNIT *uptr)
|
||||||
|
{
|
||||||
|
t_stat r;
|
||||||
|
|
||||||
|
r = detach_unit (uptr);
|
||||||
|
if ((uptr->flags & UNIT_ATT) == 0)
|
||||||
|
uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
29
sim_timer.c
29
sim_timer.c
|
@ -152,8 +152,7 @@ return sim_os_msec () - stime;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(SIM_ASYNCH_IO)
|
#if defined(SIM_ASYNCH_IO)
|
||||||
#ifndef CLOCK_REALTIME
|
#ifdef NEED_CLOCK_REALTIME
|
||||||
#define CLOCK_REALTIME 1
|
|
||||||
int clock_gettime(int clk_id, struct timespec *tp)
|
int clock_gettime(int clk_id, struct timespec *tp)
|
||||||
{
|
{
|
||||||
uint32 secs, ns, tod[2], unixbase[2] = {0xd53e8000, 0x019db1de};
|
uint32 secs, ns, tod[2], unixbase[2] = {0xd53e8000, 0x019db1de};
|
||||||
|
@ -225,12 +224,13 @@ Sleep (msec);
|
||||||
return sim_os_msec () - stime;
|
return sim_os_msec () - stime;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(CLOCK_REALTIME) && defined (SIM_ASYNCH_IO)
|
#if defined(NEED_CLOCK_REALTIME)
|
||||||
#define CLOCK_REALTIME 1
|
|
||||||
int clock_gettime(int clk_id, struct timespec *tp)
|
int clock_gettime(int clk_id, struct timespec *tp)
|
||||||
{
|
{
|
||||||
t_uint64 now, unixbase;
|
t_uint64 now, unixbase;
|
||||||
|
|
||||||
|
if (clk_id != CLOCK_REALTIME)
|
||||||
|
return -1;
|
||||||
unixbase = 116444736;
|
unixbase = 116444736;
|
||||||
unixbase *= 1000000000;
|
unixbase *= 1000000000;
|
||||||
GetSystemTimeAsFileTime((FILETIME*)&now);
|
GetSystemTimeAsFileTime((FILETIME*)&now);
|
||||||
|
@ -315,8 +315,7 @@ treq.tv_nsec = (milliseconds % MILLIS_PER_SEC) * NANOS_PER_MILLI;
|
||||||
return sim_os_msec () - stime;
|
return sim_os_msec () - stime;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(CLOCK_REALTIME) && defined (SIM_ASYNCH_IO)
|
#if defined(NEED_CLOCK_REALTIME)
|
||||||
#define CLOCK_REALTIME 1
|
|
||||||
int clock_gettime(int clk_id, struct timespec *tp)
|
int clock_gettime(int clk_id, struct timespec *tp)
|
||||||
{
|
{
|
||||||
struct timeval cur;
|
struct timeval cur;
|
||||||
|
@ -377,8 +376,7 @@ if (tim > SIM_IDLE_MAX)
|
||||||
return tim;
|
return tim;
|
||||||
}
|
}
|
||||||
#if !defined(_POSIX_SOURCE) && defined(SIM_ASYNCH_IO)
|
#if !defined(_POSIX_SOURCE) && defined(SIM_ASYNCH_IO)
|
||||||
#ifndef CLOCK_REALTIME
|
#ifdef NEED_CLOCK_REALTIME
|
||||||
#define CLOCK_REALTIME 1
|
|
||||||
typedef int clockid_t;
|
typedef int clockid_t;
|
||||||
int clock_gettime(clockid_t clk_id, struct timespec *tp)
|
int clock_gettime(clockid_t clk_id, struct timespec *tp)
|
||||||
{
|
{
|
||||||
|
@ -408,6 +406,21 @@ return sim_os_msec () - stime;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* diff = min - sub */
|
||||||
|
void
|
||||||
|
sim_timespec_diff (struct timespec *diff, struct timespec *min, struct timespec *sub)
|
||||||
|
{
|
||||||
|
/* move the minuend value to the difference and operate there. */
|
||||||
|
*diff = *min;
|
||||||
|
/* Borrow as needed for the nsec value */
|
||||||
|
if (sub->tv_nsec > min->tv_nsec) {
|
||||||
|
--diff->tv_sec;
|
||||||
|
diff->tv_nsec += 1000000000;
|
||||||
|
}
|
||||||
|
diff->tv_nsec -= sub->tv_nsec;
|
||||||
|
diff->tv_sec -= sub->tv_sec;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(SIM_ASYNCH_IO)
|
#if defined(SIM_ASYNCH_IO)
|
||||||
uint32 sim_idle_ms_sleep (unsigned int msec)
|
uint32 sim_idle_ms_sleep (unsigned int msec)
|
||||||
{
|
{
|
||||||
|
|
10
sim_timer.h
10
sim_timer.h
|
@ -31,6 +31,15 @@
|
||||||
#ifndef _SIM_TIMER_H_
|
#ifndef _SIM_TIMER_H_
|
||||||
#define _SIM_TIMER_H_ 0
|
#define _SIM_TIMER_H_ 0
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#ifndef CLOCK_REALTIME
|
||||||
|
#define CLOCK_REALTIME 1
|
||||||
|
#define NEED_CLOCK_REALTIME 1
|
||||||
|
int clock_gettime(int clock_id, struct timespec *tp);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define SIM_NTIMERS 8 /* # timers */
|
#define SIM_NTIMERS 8 /* # timers */
|
||||||
#define SIM_TMAX 500 /* max timer makeup */
|
#define SIM_TMAX 500 /* max timer makeup */
|
||||||
|
|
||||||
|
@ -51,6 +60,7 @@
|
||||||
#define SIM_THROT_PCT 3
|
#define SIM_THROT_PCT 3
|
||||||
|
|
||||||
t_bool sim_timer_init (void);
|
t_bool sim_timer_init (void);
|
||||||
|
void sim_timespec_diff (struct timespec *diff, struct timespec *min, struct timespec *sub);
|
||||||
int32 sim_rtcn_init (int32 time, int32 tmr);
|
int32 sim_rtcn_init (int32 time, int32 tmr);
|
||||||
void sim_rtcn_init_all (void);
|
void sim_rtcn_init_all (void);
|
||||||
int32 sim_rtcn_calb (int32 ticksper, int32 tmr);
|
int32 sim_rtcn_calb (int32 ticksper, int32 tmr);
|
||||||
|
|
Loading…
Add table
Reference in a new issue