VAX730, VAX750, VAX8600: Update Interval Timer and TODR to align with VAX780
This commit is contained in:
parent
5fc4744d8a
commit
76103cf760
4 changed files with 384 additions and 374 deletions
|
@ -100,6 +100,18 @@
|
|||
#define CLK_DELAY 5000 /* 100 Hz */
|
||||
#define TMXR_MULT 1 /* 100 Hz */
|
||||
|
||||
static BITFIELD tmr_iccs_bits [] = {
|
||||
BIT(RUN), /* Run */
|
||||
BITNCF(3), /* unused */
|
||||
BIT(XFR), /* Transfer */
|
||||
BIT(SGL), /* Single */
|
||||
BIT(IE), /* Interrupt Enable */
|
||||
BIT(DON), /* Done */
|
||||
BITNCF(23), /* unused */
|
||||
BIT(ERR), /* Error */
|
||||
ENDBITS
|
||||
};
|
||||
|
||||
/* TU58 definitions */
|
||||
|
||||
#define UNIT_V_WLK (UNIT_V_UF) /* write locked */
|
||||
|
@ -173,13 +185,13 @@ uint32 tmr_nicr = 0; /* next interval */
|
|||
uint32 tmr_inc = 0; /* timer increment */
|
||||
int32 tmr_sav = 0; /* timer save */
|
||||
int32 tmr_int = 0; /* interrupt */
|
||||
int32 tmr_use_100hz = 1; /* use 100Hz for timer */
|
||||
int32 clk_tps = 100; /* ticks/second */
|
||||
int32 tmxr_poll = CLK_DELAY * TMXR_MULT; /* term mux poll */
|
||||
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;
|
||||
|
||||
|
@ -187,7 +199,6 @@ int32 td_regval; /* temp location used in
|
|||
|
||||
t_stat tti_svc (UNIT *uptr);
|
||||
t_stat tto_svc (UNIT *uptr);
|
||||
t_stat clk_svc (UNIT *uptr);
|
||||
t_stat tmr_svc (UNIT *uptr);
|
||||
t_stat tti_reset (DEVICE *dptr);
|
||||
t_stat tto_reset (DEVICE *dptr);
|
||||
|
@ -204,9 +215,8 @@ t_stat clk_attach (UNIT *uptr, CONST char *cptr);
|
|||
t_stat clk_detach (UNIT *uptr);
|
||||
t_stat tmr_reset (DEVICE *dptr);
|
||||
t_stat td_reset (DEVICE *dptr);
|
||||
int32 icr_rd (t_bool interp);
|
||||
void tmr_incr (uint32 inc);
|
||||
void tmr_sched (void);
|
||||
int32 icr_rd (void);
|
||||
void tmr_sched (uint32 incr);
|
||||
t_stat todr_resync (void);
|
||||
t_stat txdb_misc_wr (int32 data);
|
||||
|
||||
|
@ -283,7 +293,7 @@ DEVICE tto_dev = {
|
|||
|
||||
/* TODR and TMR data structures */
|
||||
|
||||
UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE+UNIT_FIX, sizeof(TOY)), CLK_DELAY };/* 100Hz */
|
||||
UNIT clk_unit = { UDATA (NULL, UNIT_IDLE+UNIT_FIX, sizeof(TOY))};
|
||||
|
||||
REG clk_reg[] = {
|
||||
{ DRDATAD (TIME, clk_unit.wait, 24, "initial poll interval"), REG_NZ + PV_LEFT },
|
||||
|
@ -315,16 +325,31 @@ REG tmr_reg[] = {
|
|||
{ FLDATAD (INT, tmr_int, 0, "interrupt request") },
|
||||
{ HRDATA (INCR, tmr_inc, 32), REG_HIDDEN },
|
||||
{ HRDATA (SAVE, tmr_sav, 32), REG_HIDDEN },
|
||||
{ FLDATA (USE100HZ, tmr_use_100hz, 0), REG_HIDDEN },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
#define TMR_DB_REG 0x01 /* Register Access */
|
||||
#define TMR_DB_TICK 0x02 /* Ticks */
|
||||
#define TMR_DB_SCHED 0x04 /* Scheduling */
|
||||
#define TMR_DB_INT 0x08 /* Interrupts */
|
||||
#define TMR_DB_TODR 0x10 /* TODR */
|
||||
|
||||
DEBTAB tmr_deb[] = {
|
||||
{ "REG", TMR_DB_REG, "Register Access"},
|
||||
{ "TICK", TMR_DB_TICK, "Ticks"},
|
||||
{ "SCHED", TMR_DB_SCHED, "Ticks"},
|
||||
{ "INT", TMR_DB_INT, "Interrupts"},
|
||||
{ "TODR", TMR_DB_TODR, "TODR activities"},
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
DEVICE tmr_dev = {
|
||||
"TMR", &tmr_unit, tmr_reg, NULL,
|
||||
1, 0, 0, 0, 0, 0,
|
||||
NULL, NULL, &tmr_reset,
|
||||
NULL, NULL, NULL,
|
||||
NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL, DEV_DEBUG, 0,
|
||||
tmr_deb, NULL, NULL, NULL, NULL, NULL,
|
||||
&tmr_description
|
||||
};
|
||||
|
||||
|
@ -464,10 +489,11 @@ void rxcs_wr (int32 data)
|
|||
{
|
||||
if ((data & CSR_IE) == 0)
|
||||
tti_int = 0;
|
||||
else if ((tti_csr & (CSR_DONE + CSR_IE)) == CSR_DONE)
|
||||
tti_int = 1;
|
||||
else {
|
||||
if ((tti_csr & (CSR_DONE + CSR_IE)) == CSR_DONE)
|
||||
tti_int = 1;
|
||||
}
|
||||
tti_csr = (tti_csr & ~RXCS_WR) | (data & RXCS_WR);
|
||||
return;
|
||||
}
|
||||
|
||||
int32 rxdb_rd (void)
|
||||
|
@ -492,10 +518,11 @@ void txcs_wr (int32 data)
|
|||
{
|
||||
if ((data & CSR_IE) == 0)
|
||||
tto_int = 0;
|
||||
else if ((tto_csr & (CSR_DONE + CSR_IE)) == CSR_DONE)
|
||||
tto_int = 1;
|
||||
else {
|
||||
if ((tto_csr & (CSR_DONE + CSR_IE)) == CSR_DONE)
|
||||
tto_int = 1;
|
||||
}
|
||||
tto_csr = (tto_csr & ~TXCS_WR) | (data & TXCS_WR);
|
||||
return;
|
||||
}
|
||||
|
||||
void txdb_wr (int32 data)
|
||||
|
@ -506,7 +533,6 @@ tto_int = 0; /* clear int */
|
|||
if (tto_buf & TXDB_SEL) /* console mailbox? */
|
||||
txdb_misc_wr (tto_buf);
|
||||
sim_activate (&tto_unit, tto_unit.wait); /* no, console */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Terminal input service (poll for character) */
|
||||
|
@ -524,7 +550,8 @@ if ((c = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */
|
|||
return c;
|
||||
if (c & SCPE_BREAK) /* break? */
|
||||
tti_buf = RXDB_ERR;
|
||||
else tti_buf = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags));
|
||||
else
|
||||
tti_buf = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags));
|
||||
tti_buftime = sim_os_msec ();
|
||||
uptr->pos = uptr->pos + 1;
|
||||
tti_csr = tti_csr | CSR_DONE;
|
||||
|
@ -541,7 +568,7 @@ tmxr_set_console_units (&tti_unit, &tto_unit);
|
|||
tti_buf = 0;
|
||||
tti_csr = 0;
|
||||
tti_int = 0;
|
||||
sim_activate_abs (&tti_unit, KBD_WAIT (tti_unit.wait, tmr_poll));
|
||||
sim_activate (&tti_unit, KBD_WAIT (tti_unit.wait, tmr_poll));
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
@ -612,162 +639,143 @@ return "console terminal output";
|
|||
|
||||
The architected VAX timer, which increments at 1Mhz, cannot be
|
||||
accurately simulated due to the overhead that would be required
|
||||
for 1M clock events per second. Instead, a hidden calibrated
|
||||
100Hz timer is run (because that's what VMS expects), and a
|
||||
hack is used for the interval timer.
|
||||
|
||||
When the timer is started, the timer interval is inspected.
|
||||
|
||||
if the interval is >= 10msec, then the 100Hz timer drives the
|
||||
next interval
|
||||
if the interval is < 10mec, then count instructions
|
||||
for 1M clock events per second. Instead 1Mhz intervals are
|
||||
derived from the calibrated instruction execution rate.
|
||||
|
||||
If the interval register is read, then its value between events
|
||||
is interpolated using the current instruction count versus the
|
||||
count when the most recent event started, the result is scaled
|
||||
to the calibrated system clock, unless the interval being timed
|
||||
is less than a calibrated system clock tick (or the calibrated
|
||||
clock is running very slowly) at which time the result will be
|
||||
the elapsed instruction count.
|
||||
is interpolated relative to the elapsed instruction count.
|
||||
*/
|
||||
|
||||
int32 iccs_rd (void)
|
||||
{
|
||||
sim_debug_bits_hdr (TMR_DB_REG, &tmr_dev, "iccs_rd()", tmr_iccs_bits, tmr_iccs, tmr_iccs, TRUE);
|
||||
return tmr_iccs & TMR_CSR_RD;
|
||||
}
|
||||
|
||||
void iccs_wr (int32 val)
|
||||
{
|
||||
sim_debug_bits_hdr (TMR_DB_REG, &tmr_dev, "iccs_wr()", tmr_iccs_bits, tmr_iccs, val, TRUE);
|
||||
if ((val & TMR_CSR_RUN) == 0) { /* clearing run? */
|
||||
sim_cancel (&tmr_unit); /* cancel timer */
|
||||
tmr_use_100hz = 0;
|
||||
if (tmr_iccs & TMR_CSR_RUN) /* run 1 -> 0? */
|
||||
tmr_icr = icr_rd (TRUE); /* update itr */
|
||||
if (tmr_iccs & TMR_CSR_RUN) { /* run 1 -> 0? */
|
||||
tmr_icr = icr_rd (); /* update itr */
|
||||
sim_rtcn_calb (0, TMR_CLK); /* stop timer */
|
||||
}
|
||||
}
|
||||
if (val & CSR_DONE) /* Interrupt Acked? */
|
||||
sim_rtcn_tick_ack (20, TMR_CLK); /* Let timers know */
|
||||
tmr_iccs = tmr_iccs & ~(val & TMR_CSR_W1C); /* W1C csr */
|
||||
tmr_iccs = (tmr_iccs & ~TMR_CSR_WR) | /* new r/w */
|
||||
(val & TMR_CSR_WR);
|
||||
if (val & TMR_CSR_XFR) tmr_icr = tmr_nicr; /* xfr set? */
|
||||
if (val & TMR_CSR_XFR) /* xfr set? */
|
||||
tmr_icr = tmr_nicr;
|
||||
if (val & TMR_CSR_RUN) { /* run? */
|
||||
if (val & TMR_CSR_XFR) /* new tir? */
|
||||
sim_cancel (&tmr_unit); /* stop prev */
|
||||
if (!sim_is_active (&tmr_unit)) /* not running? */
|
||||
tmr_sched (); /* activate */
|
||||
if (!sim_is_active (&tmr_unit)) { /* not running? */
|
||||
sim_rtcn_init_unit (&tmr_unit, CLK_DELAY, TMR_CLK); /* init timer */
|
||||
tmr_sched (tmr_icr); /* activate */
|
||||
}
|
||||
}
|
||||
else if (val & TMR_CSR_SGL) { /* single step? */
|
||||
tmr_incr (1); /* incr tmr */
|
||||
if (tmr_icr == 0) /* if ovflo, */
|
||||
tmr_icr = tmr_nicr; /* reload tir */
|
||||
else {
|
||||
if (val & TMR_CSR_XFR) /* xfr set? */
|
||||
tmr_icr = tmr_nicr;
|
||||
if (val & TMR_CSR_SGL) { /* single step? */
|
||||
tmr_icr = tmr_icr + 1; /* incr tmr */
|
||||
if (tmr_icr == 0) { /* if ovflo, */
|
||||
if (tmr_iccs & TMR_CSR_DON) /* done? set err */
|
||||
tmr_iccs = tmr_iccs | TMR_CSR_ERR;
|
||||
else
|
||||
tmr_iccs = tmr_iccs | TMR_CSR_DON; /* set done */
|
||||
if (tmr_iccs & TMR_CSR_IE) { /* ie? */
|
||||
tmr_int = 1; /* set int req */
|
||||
sim_debug (TMR_DB_INT, &tmr_dev, "tmr_incr() - INT=1\n");
|
||||
}
|
||||
tmr_icr = tmr_nicr; /* reload tir */
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((tmr_iccs & (TMR_CSR_DON | TMR_CSR_IE)) != /* update int */
|
||||
(TMR_CSR_DON | TMR_CSR_IE))
|
||||
tmr_int = 0;
|
||||
return;
|
||||
(TMR_CSR_DON | TMR_CSR_IE)) {
|
||||
if (tmr_int) {
|
||||
tmr_int = 0;
|
||||
sim_debug (TMR_DB_INT, &tmr_dev, "iccs_wr() - INT=0\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32 icr_rd (t_bool interp)
|
||||
int32 icr_rd (void)
|
||||
{
|
||||
uint32 delta;
|
||||
int32 result;
|
||||
|
||||
if (interp || (tmr_iccs & TMR_CSR_RUN)) { /* interp, running? */
|
||||
delta = sim_grtime () - tmr_sav; /* delta inst */
|
||||
if (tmr_use_100hz && (tmr_poll > TMR_INC)) /* scale large int */
|
||||
delta = (uint32) ((((double) delta) * TMR_INC) / tmr_poll);
|
||||
if (delta >= tmr_inc)
|
||||
delta = tmr_inc - 1;
|
||||
return tmr_icr + delta;
|
||||
if (tmr_iccs & TMR_CSR_RUN) { /* running? */
|
||||
uint32 delta = sim_grtime() - tmr_sav;
|
||||
result = (int32)(tmr_nicr + (uint32)((1000000.0 * delta) / sim_timer_inst_per_sec ()));
|
||||
}
|
||||
return tmr_icr;
|
||||
else
|
||||
result = (int32)tmr_icr;
|
||||
sim_debug (TMR_DB_REG, &tmr_dev, "icr_rd() = 0x%08X%s\n", result, (tmr_iccs & TMR_CSR_RUN) ? " - interpolated" : "");
|
||||
return result;
|
||||
}
|
||||
|
||||
int32 nicr_rd (void)
|
||||
{
|
||||
sim_debug (TMR_DB_REG, &tmr_dev, "nicr_rd() = 0x%08X\n", tmr_nicr);
|
||||
return tmr_nicr;
|
||||
}
|
||||
|
||||
void nicr_wr (int32 val)
|
||||
{
|
||||
sim_debug (TMR_DB_REG, &tmr_dev, "nicr_wr(0x%08X)\n", val);
|
||||
tmr_nicr = val;
|
||||
}
|
||||
|
||||
/* 100Hz base clock unit service */
|
||||
|
||||
t_stat clk_svc (UNIT *uptr)
|
||||
{
|
||||
tmr_poll = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */
|
||||
sim_activate_after (uptr, 1000000/clk_tps); /* reactivate unit */
|
||||
tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */
|
||||
AIO_SET_INTERRUPT_LATENCY(tmr_poll*clk_tps); /* set interrrupt latency */
|
||||
if ((tmr_iccs & TMR_CSR_RUN) && tmr_use_100hz) /* timer on, std intvl? */
|
||||
tmr_incr (TMR_INC); /* do timer service */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Interval timer unit service */
|
||||
|
||||
t_stat tmr_svc (UNIT *uptr)
|
||||
{
|
||||
tmr_incr (tmr_inc); /* incr timer */
|
||||
sim_debug (TMR_DB_TICK, &tmr_dev, "tmr_svc()\n");
|
||||
tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */
|
||||
if (tmr_iccs & TMR_CSR_DON) /* done? set err */
|
||||
tmr_iccs = tmr_iccs | TMR_CSR_ERR;
|
||||
else
|
||||
tmr_iccs = tmr_iccs | TMR_CSR_DON; /* set done */
|
||||
if (tmr_iccs & TMR_CSR_RUN) /* run? */
|
||||
tmr_sched (tmr_nicr); /* reactivate */
|
||||
if (tmr_iccs & TMR_CSR_IE) { /* ie? set int req */
|
||||
tmr_int = 1;
|
||||
sim_debug (TMR_DB_INT, &tmr_dev, "tmr_svc() - INT=1\n");
|
||||
}
|
||||
else
|
||||
tmr_int = 0;
|
||||
AIO_SET_INTERRUPT_LATENCY(tmr_poll*clk_tps); /* set interrrupt latency */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Timer increment */
|
||||
|
||||
void tmr_incr (uint32 inc)
|
||||
{
|
||||
uint32 new_icr = (tmr_icr + inc) & LMASK; /* add incr */
|
||||
|
||||
if (new_icr < tmr_icr) { /* ovflo? */
|
||||
tmr_icr = 0; /* now 0 */
|
||||
if (tmr_iccs & TMR_CSR_DON) /* done? set err */
|
||||
tmr_iccs = tmr_iccs | TMR_CSR_ERR;
|
||||
else tmr_iccs = tmr_iccs | TMR_CSR_DON; /* set done */
|
||||
if (tmr_iccs & TMR_CSR_RUN) { /* run? */
|
||||
tmr_icr = tmr_nicr; /* reload */
|
||||
tmr_sched (); /* reactivate */
|
||||
}
|
||||
if (tmr_iccs & TMR_CSR_IE) /* ie? set int req */
|
||||
tmr_int = 1;
|
||||
else tmr_int = 0;
|
||||
}
|
||||
else {
|
||||
tmr_icr = new_icr; /* no, update icr */
|
||||
if (tmr_iccs & TMR_CSR_RUN) /* still running? */
|
||||
tmr_sched (); /* reactivate */
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Timer scheduling */
|
||||
|
||||
void tmr_sched (void)
|
||||
void tmr_sched (uint32 nicr)
|
||||
{
|
||||
tmr_sav = sim_grtime (); /* save intvl base */
|
||||
tmr_inc = (~tmr_icr + 1); /* inc = interval */
|
||||
if (tmr_inc == 0) tmr_inc = 1;
|
||||
if (tmr_inc < TMR_INC) { /* 100Hz multiple? */
|
||||
sim_activate (&tmr_unit, tmr_inc); /* schedule timer */
|
||||
tmr_use_100hz = 0;
|
||||
}
|
||||
else tmr_use_100hz = 1; /* let clk handle */
|
||||
return;
|
||||
uint32 usecs = (nicr) ? (~nicr + 1) : 0xFFFFFFFF;
|
||||
|
||||
clk_tps = 1000000 / usecs;
|
||||
|
||||
sim_debug (TMR_DB_SCHED, &tmr_dev, "tmr_sched(nicr=0x%08X-usecs=0x%08X) - tps=%d\n", nicr, usecs, clk_tps);
|
||||
tmr_poll = sim_rtcn_calb (clk_tps, TMR_CLK);
|
||||
if (SCPE_OK == sim_activate_after (&tmr_unit, usecs))
|
||||
tmr_sav = sim_grtime(); /* Save interval base time */
|
||||
}
|
||||
|
||||
/* 100Hz clock reset */
|
||||
/* 100Hz TODR reset */
|
||||
|
||||
t_stat clk_reset (DEVICE *dptr)
|
||||
{
|
||||
tmr_poll = sim_rtcn_init_unit (&clk_unit, clk_unit.wait, TMR_CLK);/* init 100Hz timer */
|
||||
sim_activate_after (&clk_unit, 1000000/clk_tps); /* activate 100Hz unit */
|
||||
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 ();
|
||||
}
|
||||
todr_resync ();
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
@ -807,6 +815,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)
|
||||
|
@ -818,8 +840,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;
|
||||
}
|
||||
|
||||
|
@ -839,13 +874,12 @@ return r;
|
|||
|
||||
t_stat tmr_reset (DEVICE *dptr)
|
||||
{
|
||||
tmr_poll = sim_rtcn_init_unit (&tmr_unit, CLK_DELAY, TMR_CLK); /* init timer */
|
||||
tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */
|
||||
tmr_iccs = 0;
|
||||
tmr_icr = 0;
|
||||
tmr_nicr = 0;
|
||||
tmr_int = 0;
|
||||
tmr_use_100hz = 1;
|
||||
sim_cancel (&tmr_unit); /* cancel timer */
|
||||
todr_resync (); /* resync TODR */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
@ -865,6 +899,7 @@ 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);
|
||||
sim_debug (TMR_DB_TODR, &tmr_dev, "todr_rd() - TODR=0x%X\n", (int32)(val.tv_sec*100 + val.tv_nsec/10000000));
|
||||
return (int32)(val.tv_sec*100 + val.tv_nsec/10000000); /* 100hz Clock Ticks */
|
||||
}
|
||||
|
||||
|
@ -882,6 +917,7 @@ 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_debug (TMR_DB_TODR, &tmr_dev, "todr_wr(0x%X)\n", data);
|
||||
}
|
||||
|
||||
t_stat todr_resync (void)
|
||||
|
@ -904,9 +940,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;
|
||||
|
|
|
@ -175,7 +175,6 @@ uint32 tmr_nicr = 0; /* next interval */
|
|||
uint32 tmr_inc = 0; /* timer increment */
|
||||
int32 tmr_sav = 0; /* timer save */
|
||||
int32 tmr_int = 0; /* interrupt */
|
||||
int32 tmr_use_100hz = 1; /* use 100Hz for timer */
|
||||
int32 clk_tps = 100; /* ticks/second */
|
||||
int32 tmxr_poll = CLK_DELAY * TMXR_MULT; /* term mux poll */
|
||||
int32 tmr_poll = CLK_DELAY; /* pgm timer poll */
|
||||
|
@ -190,7 +189,6 @@ int32 td_regval; /* temp location used in
|
|||
|
||||
t_stat tti_svc (UNIT *uptr);
|
||||
t_stat tto_svc (UNIT *uptr);
|
||||
t_stat clk_svc (UNIT *uptr);
|
||||
t_stat tmr_svc (UNIT *uptr);
|
||||
t_stat tti_reset (DEVICE *dptr);
|
||||
t_stat tto_reset (DEVICE *dptr);
|
||||
|
@ -207,9 +205,9 @@ t_stat tmr_reset (DEVICE *dptr);
|
|||
const char *tmr_description (DEVICE *dptr);
|
||||
t_stat td_reset (DEVICE *dptr);
|
||||
const char *td_description (DEVICE *dptr);
|
||||
int32 icr_rd (t_bool interp);
|
||||
int32 icr_rd (void);
|
||||
void tmr_incr (uint32 inc);
|
||||
void tmr_sched (void);
|
||||
void tmr_sched (uint32 incr);
|
||||
t_stat todr_resync (void);
|
||||
t_stat txdb_misc_wr (int32 data);
|
||||
|
||||
|
@ -288,12 +286,12 @@ DEVICE tto_dev = {
|
|||
|
||||
/* TODR and TMR data structures */
|
||||
|
||||
UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE+UNIT_FIX, sizeof(TOY)), CLK_DELAY };/* 100Hz */
|
||||
UNIT clk_unit = { UDATA (NULL, UNIT_IDLE+UNIT_FIX, sizeof(TOY))};
|
||||
|
||||
REG clk_reg[] = {
|
||||
{ DRDATAD (TIME, clk_unit.wait, 24, "initial poll interval"), REG_NZ + PV_LEFT },
|
||||
{ DRDATAD (POLL, tmr_poll, 24, "calibrated poll interval"), REG_NZ + PV_LEFT + REG_HRO },
|
||||
{ DRDATAD (TPS, clk_tps, 8, "ticks per second (100)"), REG_NZ + PV_LEFT },
|
||||
{ DRDATAD (TPS, clk_tps, 8, "ticks per second"), REG_NZ + PV_LEFT },
|
||||
#if defined (SIM_ASYNCH_IO)
|
||||
{ DRDATAD (ASYNCH, sim_asynch_enabled, 1, "asynch I/O enabled flag"), PV_LEFT },
|
||||
{ DRDATAD (LATENCY, sim_asynch_latency, 32, "desired asynch interrupt latency"), PV_LEFT },
|
||||
|
@ -320,7 +318,6 @@ REG tmr_reg[] = {
|
|||
{ FLDATAD (INT, tmr_int, 0, "interrupt request") },
|
||||
{ HRDATA (INCR, tmr_inc, 32), REG_HIDDEN },
|
||||
{ HRDATA (SAVE, tmr_sav, 32), REG_HIDDEN },
|
||||
{ FLDATA (USE100HZ, tmr_use_100hz, 0), REG_HIDDEN },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
@ -328,12 +325,14 @@ REG tmr_reg[] = {
|
|||
#define TMR_DB_TICK 0x02 /* Ticks */
|
||||
#define TMR_DB_SCHED 0x04 /* Scheduling */
|
||||
#define TMR_DB_INT 0x08 /* Interrupts */
|
||||
#define TMR_DB_TODR 0x10 /* TODR */
|
||||
|
||||
DEBTAB tmr_deb[] = {
|
||||
{ "REG", TMR_DB_REG, "Register Access"},
|
||||
{ "TICK", TMR_DB_TICK, "Ticks"},
|
||||
{ "SCHED", TMR_DB_SCHED, "Ticks"},
|
||||
{ "INT", TMR_DB_INT, "Interrupts"},
|
||||
{ "TODR", TMR_DB_TODR, "TODR activities"},
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
|
@ -484,10 +483,11 @@ void rxcs_wr (int32 data)
|
|||
{
|
||||
if ((data & CSR_IE) == 0)
|
||||
tti_int = 0;
|
||||
else if ((tti_csr & (CSR_DONE + CSR_IE)) == CSR_DONE)
|
||||
tti_int = 1;
|
||||
else {
|
||||
if ((tti_csr & (CSR_DONE + CSR_IE)) == CSR_DONE)
|
||||
tti_int = 1;
|
||||
}
|
||||
tti_csr = (tti_csr & ~RXCS_WR) | (data & RXCS_WR);
|
||||
return;
|
||||
}
|
||||
|
||||
int32 rxdb_rd (void)
|
||||
|
@ -512,10 +512,11 @@ void txcs_wr (int32 data)
|
|||
{
|
||||
if ((data & CSR_IE) == 0)
|
||||
tto_int = 0;
|
||||
else if ((tto_csr & (CSR_DONE + CSR_IE)) == CSR_DONE)
|
||||
tto_int = 1;
|
||||
else {
|
||||
if ((tto_csr & (CSR_DONE + CSR_IE)) == CSR_DONE)
|
||||
tto_int = 1;
|
||||
}
|
||||
tto_csr = (tto_csr & ~TXCS_WR) | (data & TXCS_WR);
|
||||
return;
|
||||
}
|
||||
|
||||
void txdb_wr (int32 data)
|
||||
|
@ -525,8 +526,8 @@ tto_csr = tto_csr & ~CSR_DONE; /* clear flag */
|
|||
tto_int = 0; /* clear int */
|
||||
if (tto_buf & TXDB_SEL) /* console? */
|
||||
txdb_misc_wr (tto_buf);
|
||||
else sim_activate (&tto_unit, tto_unit.wait); /* no, console terminal */
|
||||
return;
|
||||
else
|
||||
sim_activate (&tto_unit, tto_unit.wait); /* no, console terminal */
|
||||
}
|
||||
|
||||
/* Terminal input service (poll for character) */
|
||||
|
@ -535,7 +536,7 @@ t_stat tti_svc (UNIT *uptr)
|
|||
{
|
||||
int32 c;
|
||||
|
||||
sim_clock_coschedule_tmr (uptr, TMR_CLK, TMXR_MULT); /* continue poll */
|
||||
sim_clock_coschedule (uptr, TMXR_MULT); /* continue poll */
|
||||
|
||||
if ((tti_csr & CSR_DONE) && /* input still pending and < 500ms? */
|
||||
((sim_os_msec () - tti_buftime) < 500))
|
||||
|
@ -544,7 +545,8 @@ if ((c = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */
|
|||
return c;
|
||||
if (c & SCPE_BREAK) /* break? */
|
||||
tti_buf = RXDB_ERR | RXDB_FRM;
|
||||
else tti_buf = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags));
|
||||
else
|
||||
tti_buf = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags));
|
||||
tti_buftime = sim_os_msec ();
|
||||
uptr->pos = uptr->pos + 1;
|
||||
tti_csr = tti_csr | CSR_DONE;
|
||||
|
@ -561,7 +563,7 @@ tmxr_set_console_units (&tti_unit, &tto_unit);
|
|||
tti_buf = 0;
|
||||
tti_csr = 0;
|
||||
tti_int = 0;
|
||||
sim_activate_abs (&tti_unit, KBD_WAIT (tti_unit.wait, tmr_poll));
|
||||
sim_activate (&tti_unit, KBD_WAIT (tti_unit.wait, tmr_poll));
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
@ -633,23 +635,11 @@ return "console terminal output";
|
|||
|
||||
The architected VAX timer, which increments at 1Mhz, cannot be
|
||||
accurately simulated due to the overhead that would be required
|
||||
for 1M clock events per second. Instead, a hidden calibrated
|
||||
100Hz timer is run (because that's what VMS expects), and a
|
||||
hack is used for the interval timer.
|
||||
|
||||
When the timer is started, the timer interval is inspected.
|
||||
|
||||
if the interval is >= 10msec, then the 100Hz timer drives the
|
||||
next interval
|
||||
if the interval is < 10mec, then count instructions
|
||||
for 1M clock events per second. Instead 1Mhz intervals are
|
||||
derived from the calibrated instruction execution rate.
|
||||
|
||||
If the interval register is read, then its value between events
|
||||
is interpolated using the current instruction count versus the
|
||||
count when the most recent event started, the result is scaled
|
||||
to the calibrated system clock, unless the interval being timed
|
||||
is less than a calibrated system clock tick (or the calibrated
|
||||
clock is running very slowly) at which time the result will be
|
||||
the elapsed instruction count.
|
||||
is interpolated relative to the elapsed instruction count.
|
||||
*/
|
||||
|
||||
int32 iccs_rd (void)
|
||||
|
@ -660,29 +650,46 @@ return tmr_iccs & TMR_CSR_RD;
|
|||
|
||||
void iccs_wr (int32 val)
|
||||
{
|
||||
sim_debug_bits_hdr (TMR_DB_REG, &tmr_dev, "iccs_wr()", tmr_iccs_bits, val, val, TRUE);
|
||||
sim_debug_bits_hdr (TMR_DB_REG, &tmr_dev, "iccs_wr()", tmr_iccs_bits, tmr_iccs, val, TRUE);
|
||||
if ((val & TMR_CSR_RUN) == 0) { /* clearing run? */
|
||||
sim_cancel (&tmr_unit); /* cancel timer */
|
||||
tmr_use_100hz = 0;
|
||||
if (tmr_iccs & TMR_CSR_RUN) /* run 1 -> 0? */
|
||||
tmr_icr = icr_rd (TRUE); /* update itr */
|
||||
if (tmr_iccs & TMR_CSR_RUN) { /* run 1 -> 0? */
|
||||
tmr_icr = icr_rd (); /* update itr */
|
||||
sim_rtcn_calb (0, TMR_CLK); /* stop timer */
|
||||
}
|
||||
}
|
||||
if (val & CSR_DONE) /* Interrupt Acked? */
|
||||
sim_rtcn_tick_ack (20, TMR_CLK); /* Let timers know */
|
||||
tmr_iccs = tmr_iccs & ~(val & TMR_CSR_W1C); /* W1C csr */
|
||||
tmr_iccs = (tmr_iccs & ~TMR_CSR_WR) | /* new r/w */
|
||||
(val & TMR_CSR_WR);
|
||||
if (val & TMR_CSR_XFR) tmr_icr = tmr_nicr; /* xfr set? */
|
||||
if (val & TMR_CSR_XFR) /* xfr set? */
|
||||
tmr_icr = tmr_nicr;
|
||||
if (val & TMR_CSR_RUN) { /* run? */
|
||||
if (val & TMR_CSR_XFR) /* new tir? */
|
||||
sim_cancel (&tmr_unit); /* stop prev */
|
||||
if (!sim_is_active (&tmr_unit)) /* not running? */
|
||||
tmr_sched (); /* activate */
|
||||
if (!sim_is_active (&tmr_unit)) { /* not running? */
|
||||
sim_rtcn_init_unit (&tmr_unit, CLK_DELAY, TMR_CLK); /* init timer */
|
||||
tmr_sched (tmr_icr); /* activate */
|
||||
}
|
||||
}
|
||||
else if (val & TMR_CSR_SGL) { /* single step? */
|
||||
tmr_incr (1); /* incr tmr */
|
||||
if (tmr_icr == 0) /* if ovflo, */
|
||||
tmr_icr = tmr_nicr; /* reload tir */
|
||||
else {
|
||||
if (val & TMR_CSR_XFR) /* xfr set? */
|
||||
tmr_icr = tmr_nicr;
|
||||
if (val & TMR_CSR_SGL) { /* single step? */
|
||||
tmr_icr = tmr_icr + 1; /* incr tmr */
|
||||
if (tmr_icr == 0) { /* if ovflo, */
|
||||
if (tmr_iccs & TMR_CSR_DON) /* done? set err */
|
||||
tmr_iccs = tmr_iccs | TMR_CSR_ERR;
|
||||
else
|
||||
tmr_iccs = tmr_iccs | TMR_CSR_DON; /* set done */
|
||||
if (tmr_iccs & TMR_CSR_IE) { /* ie? */
|
||||
tmr_int = 1; /* set int req */
|
||||
sim_debug (TMR_DB_INT, &tmr_dev, "tmr_incr() - INT=1\n");
|
||||
}
|
||||
tmr_icr = tmr_nicr; /* reload tir */
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((tmr_iccs & (TMR_CSR_DON | TMR_CSR_IE)) != /* update int */
|
||||
(TMR_CSR_DON | TMR_CSR_IE)) {
|
||||
|
@ -691,24 +698,20 @@ if ((tmr_iccs & (TMR_CSR_DON | TMR_CSR_IE)) != /* update int */
|
|||
sim_debug (TMR_DB_INT, &tmr_dev, "iccs_wr() - INT=0\n");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int32 icr_rd (t_bool interp)
|
||||
int32 icr_rd (void)
|
||||
{
|
||||
uint32 delta;
|
||||
int32 result;
|
||||
|
||||
if (interp || (tmr_iccs & TMR_CSR_RUN)) { /* interp, running? */
|
||||
delta = sim_grtime () - tmr_sav; /* delta inst */
|
||||
if (tmr_use_100hz && (tmr_poll > TMR_INC)) /* scale large int */
|
||||
delta = (uint32) ((((double) delta) * TMR_INC) / tmr_poll);
|
||||
if (delta >= tmr_inc)
|
||||
delta = tmr_inc - 1;
|
||||
sim_debug (TMR_DB_REG, &tmr_dev, "icr_rd() = 0x%08X\n", tmr_icr + delta);
|
||||
return tmr_icr + delta;
|
||||
if (tmr_iccs & TMR_CSR_RUN) { /* running? */
|
||||
uint32 delta = sim_grtime() - tmr_sav;
|
||||
result = (int32)(tmr_nicr + (uint32)((1000000.0 * delta) / sim_timer_inst_per_sec ()));
|
||||
}
|
||||
sim_debug (TMR_DB_REG, &tmr_dev, "icr_rd() = 0x%08X\n", tmr_icr);
|
||||
return tmr_icr;
|
||||
else
|
||||
result = (int32)tmr_icr;
|
||||
sim_debug (TMR_DB_REG, &tmr_dev, "icr_rd() = 0x%08X%s\n", result, (tmr_iccs & TMR_CSR_RUN) ? " - interpolated" : "");
|
||||
return result;
|
||||
}
|
||||
|
||||
int32 nicr_rd (void)
|
||||
|
@ -723,87 +726,52 @@ sim_debug (TMR_DB_REG, &tmr_dev, "nicr_wr(0x%08X)\n", val);
|
|||
tmr_nicr = val;
|
||||
}
|
||||
|
||||
/* 100Hz base clock unit service */
|
||||
|
||||
t_stat clk_svc (UNIT *uptr)
|
||||
{
|
||||
sim_debug (TMR_DB_TICK, &tmr_dev, "clk_svc()\n");
|
||||
tmr_poll = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */
|
||||
sim_activate_after (uptr, 1000000/clk_tps); /* reactivate unit */
|
||||
tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */
|
||||
AIO_SET_INTERRUPT_LATENCY(tmr_poll*clk_tps); /* set interrrupt latency */
|
||||
if ((tmr_iccs & TMR_CSR_RUN) && tmr_use_100hz) /* timer on, std intvl? */
|
||||
tmr_incr (TMR_INC); /* do timer service */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Interval timer unit service */
|
||||
|
||||
t_stat tmr_svc (UNIT *uptr)
|
||||
{
|
||||
sim_debug (TMR_DB_TICK, &tmr_dev, "tmr_svc()\n");
|
||||
tmr_incr (tmr_inc); /* incr timer */
|
||||
tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */
|
||||
if (tmr_iccs & TMR_CSR_DON) /* done? set err */
|
||||
tmr_iccs = tmr_iccs | TMR_CSR_ERR;
|
||||
else
|
||||
tmr_iccs = tmr_iccs | TMR_CSR_DON; /* set done */
|
||||
if (tmr_iccs & TMR_CSR_RUN) /* run? */
|
||||
tmr_sched (tmr_nicr); /* reactivate */
|
||||
if (tmr_iccs & TMR_CSR_IE) { /* ie? set int req */
|
||||
tmr_int = 1;
|
||||
sim_debug (TMR_DB_INT, &tmr_dev, "tmr_svc() - INT=1\n");
|
||||
}
|
||||
else
|
||||
tmr_int = 0;
|
||||
AIO_SET_INTERRUPT_LATENCY(tmr_poll*clk_tps); /* set interrrupt latency */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Timer increment */
|
||||
|
||||
void tmr_incr (uint32 inc)
|
||||
{
|
||||
uint32 new_icr = (tmr_icr + inc) & LMASK; /* add incr */
|
||||
|
||||
if (new_icr < tmr_icr) { /* ovflo? */
|
||||
tmr_icr = 0; /* now 0 */
|
||||
if (tmr_iccs & TMR_CSR_DON) /* done? set err */
|
||||
tmr_iccs = tmr_iccs | TMR_CSR_ERR;
|
||||
else tmr_iccs = tmr_iccs | TMR_CSR_DON; /* set done */
|
||||
if (tmr_iccs & TMR_CSR_RUN) { /* run? */
|
||||
tmr_icr = tmr_nicr; /* reload */
|
||||
tmr_sched (); /* reactivate */
|
||||
}
|
||||
if (tmr_iccs & TMR_CSR_IE) { /* ie? set int req */
|
||||
tmr_int = 1;
|
||||
sim_debug (TMR_DB_INT, &tmr_dev, "tmr_incr() - INT=1\n");
|
||||
}
|
||||
else tmr_int = 0;
|
||||
}
|
||||
else {
|
||||
tmr_icr = new_icr; /* no, update icr */
|
||||
if (tmr_iccs & TMR_CSR_RUN) /* still running? */
|
||||
tmr_sched (); /* reactivate */
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Timer scheduling */
|
||||
|
||||
void tmr_sched (void)
|
||||
void tmr_sched (uint32 nicr)
|
||||
{
|
||||
tmr_sav = sim_grtime (); /* save intvl base */
|
||||
tmr_inc = (~tmr_icr + 1); /* inc = interval */
|
||||
if (tmr_inc == 0) tmr_inc = 1;
|
||||
sim_debug (TMR_DB_SCHED, &tmr_dev, "tmr_sched(0x%08X)\n", tmr_inc);
|
||||
if (tmr_inc < TMR_INC) { /* 100Hz multiple? */
|
||||
sim_activate (&tmr_unit, tmr_inc); /* schedule timer */
|
||||
tmr_use_100hz = 0;
|
||||
}
|
||||
else tmr_use_100hz = 1; /* let clk handle */
|
||||
return;
|
||||
uint32 usecs = (nicr) ? (~nicr + 1) : 0xFFFFFFFF;
|
||||
|
||||
clk_tps = 1000000 / usecs;
|
||||
|
||||
sim_debug (TMR_DB_SCHED, &tmr_dev, "tmr_sched(nicr=0x%08X-usecs=0x%08X) - tps=%d\n", nicr, usecs, clk_tps);
|
||||
tmr_poll = sim_rtcn_calb (clk_tps, TMR_CLK);
|
||||
if (SCPE_OK == sim_activate_after (&tmr_unit, usecs))
|
||||
tmr_sav = sim_grtime(); /* Save interval base time */
|
||||
}
|
||||
|
||||
/* 100Hz clock reset */
|
||||
/* 100Hz TODR reset */
|
||||
|
||||
t_stat clk_reset (DEVICE *dptr)
|
||||
{
|
||||
tmr_poll = sim_rtcn_init_unit (&clk_unit, clk_unit.wait, TMR_CLK);/* init 100Hz timer */
|
||||
sim_activate_after (&clk_unit, 1000000/clk_tps); /* activate 100Hz unit */
|
||||
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 ();
|
||||
}
|
||||
todr_resync ();
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
@ -903,13 +871,12 @@ return r;
|
|||
|
||||
t_stat tmr_reset (DEVICE *dptr)
|
||||
{
|
||||
tmr_poll = sim_rtcn_init_unit (&tmr_unit, CLK_DELAY, TMR_CLK); /* init timer */
|
||||
tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */
|
||||
tmr_iccs = 0;
|
||||
tmr_icr = 0;
|
||||
tmr_nicr = 0;
|
||||
tmr_int = 0;
|
||||
tmr_use_100hz = 1;
|
||||
sim_cancel (&tmr_unit); /* cancel timer */
|
||||
todr_resync (); /* resync TODR */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
@ -936,7 +903,7 @@ sim_timespec_diff (&val, &now, &base);
|
|||
|
||||
if ((val.tv_sec >= TOY_MAX_SECS) || (!toy->toy_gmtbase))/* todr overflowed? */
|
||||
return 0; /* stop counting */
|
||||
|
||||
sim_debug (TMR_DB_TODR, &tmr_dev, "todr_rd() - TODR=0x%X\n", (int32)(val.tv_sec*100 + val.tv_nsec/10000000));
|
||||
return (int32)(val.tv_sec*100 + val.tv_nsec/10000000); /* 100hz Clock Ticks */
|
||||
}
|
||||
|
||||
|
@ -946,6 +913,7 @@ void todr_wr (int32 data)
|
|||
TOY *toy = (TOY *)clk_unit.filebuf;
|
||||
struct timespec now, val, base;
|
||||
|
||||
sim_debug (TMR_DB_TODR, &tmr_dev, "todr_wr(0x%X)\n", data);
|
||||
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 */
|
||||
|
|
|
@ -251,7 +251,7 @@ t_stat clk_detach (UNIT *uptr);
|
|||
t_stat tmr_reset (DEVICE *dptr);
|
||||
t_stat fl_svc (UNIT *uptr);
|
||||
t_stat fl_reset (DEVICE *dptr);
|
||||
int32 icr_rd ();
|
||||
int32 icr_rd (void);
|
||||
void tmr_sched (uint32 incr);
|
||||
t_stat todr_resync (void);
|
||||
t_stat fl_wr_txdb (int32 data);
|
||||
|
@ -453,10 +453,11 @@ void rxcs_wr (int32 data)
|
|||
{
|
||||
if ((data & CSR_IE) == 0)
|
||||
tti_int = 0;
|
||||
else if ((tti_csr & (CSR_DONE + CSR_IE)) == CSR_DONE)
|
||||
tti_int = 1;
|
||||
else {
|
||||
if ((tti_csr & (CSR_DONE + CSR_IE)) == CSR_DONE)
|
||||
tti_int = 1;
|
||||
}
|
||||
tti_csr = (tti_csr & ~RXCS_WR) | (data & RXCS_WR);
|
||||
return;
|
||||
}
|
||||
|
||||
int32 rxdb_rd (void)
|
||||
|
@ -481,10 +482,11 @@ void txcs_wr (int32 data)
|
|||
{
|
||||
if ((data & CSR_IE) == 0)
|
||||
tto_int = 0;
|
||||
else if ((tto_csr & (CSR_DONE + CSR_IE)) == CSR_DONE)
|
||||
tto_int = 1;
|
||||
else {
|
||||
if ((tto_csr & (CSR_DONE + CSR_IE)) == CSR_DONE)
|
||||
tto_int = 1;
|
||||
}
|
||||
tto_csr = (tto_csr & ~TXCS_WR) | (data & TXCS_WR);
|
||||
return;
|
||||
}
|
||||
|
||||
void txdb_wr (int32 data)
|
||||
|
@ -494,8 +496,8 @@ tto_csr = tto_csr & ~CSR_DONE; /* clear flag */
|
|||
tto_int = 0; /* clear int */
|
||||
if (tto_buf & TXDB_SEL) /* floppy? */
|
||||
fl_wr_txdb (tto_buf);
|
||||
else sim_activate (&tto_unit, tto_unit.wait); /* no, console */
|
||||
return;
|
||||
else
|
||||
sim_activate (&tto_unit, tto_unit.wait); /* no, console */
|
||||
}
|
||||
|
||||
/* Terminal input service (poll for character) */
|
||||
|
@ -513,7 +515,8 @@ if ((c = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */
|
|||
return c;
|
||||
if (c & SCPE_BREAK) /* break? */
|
||||
tti_buf = RXDB_ERR | RXDB_FRM;
|
||||
else tti_buf = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags));
|
||||
else
|
||||
tti_buf = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags));
|
||||
tti_buftime = sim_os_msec ();
|
||||
uptr->pos = uptr->pos + 1;
|
||||
tti_csr = tti_csr | CSR_DONE;
|
||||
|
@ -602,10 +605,8 @@ return "console terminal output";
|
|||
|
||||
The architected VAX timer, which increments at 1Mhz, cannot be
|
||||
accurately simulated due to the overhead that would be required
|
||||
for 1M clock events per second. Instead, a hidden calibrated
|
||||
100Hz timer is run (because that's what VMS expects), and 1Mhz
|
||||
intervals are derived from the calibrated instruction execution
|
||||
rate.
|
||||
for 1M clock events per second. Instead 1Mhz intervals are
|
||||
derived from the calibrated instruction execution rate.
|
||||
|
||||
If the interval register is read, then its value between events
|
||||
is interpolated relative to the elapsed instruction count.
|
||||
|
@ -667,10 +668,9 @@ if ((tmr_iccs & (TMR_CSR_DON | TMR_CSR_IE)) != /* update int */
|
|||
sim_debug (TMR_DB_INT, &tmr_dev, "iccs_wr() - INT=0\n");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int32 icr_rd ()
|
||||
int32 icr_rd (void)
|
||||
{
|
||||
int32 result;
|
||||
|
||||
|
@ -732,7 +732,7 @@ if (SCPE_OK == sim_activate_after (&tmr_unit, usecs))
|
|||
tmr_sav = sim_grtime(); /* Save interval base time */
|
||||
}
|
||||
|
||||
/* 100Hz clock reset */
|
||||
/* 100Hz TODR reset */
|
||||
|
||||
t_stat clk_reset (DEVICE *dptr)
|
||||
{
|
||||
|
@ -1072,7 +1072,8 @@ switch (fl_state) { /* case on state */
|
|||
tti_int = 1;
|
||||
fl_state = FL_EMPTY; /* go empty */
|
||||
}
|
||||
else fl_state = FL_DONE; /* error? cmd done */
|
||||
else
|
||||
fl_state = FL_DONE; /* error? cmd done */
|
||||
sim_activate (uptr, fl_xwait); /* schedule next */
|
||||
break;
|
||||
|
||||
|
@ -1167,7 +1168,6 @@ if ((tti_csr & CSR_DONE) == 0) { /* input idle? */
|
|||
}
|
||||
tti_buf = FL_CPROT; /* status */
|
||||
fl_state = FL_IDLE; /* floppy idle */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Reset */
|
||||
|
|
|
@ -82,6 +82,18 @@
|
|||
#define CLK_DELAY 5000 /* 100 Hz */
|
||||
#define TMXR_MULT 1 /* 100 Hz */
|
||||
|
||||
static BITFIELD tmr_iccs_bits [] = {
|
||||
BIT(RUN), /* Run */
|
||||
BITNCF(3), /* unused */
|
||||
BIT(XFR), /* Transfer */
|
||||
BIT(SGL), /* Single */
|
||||
BIT(IE), /* Interrupt Enable */
|
||||
BIT(DON), /* Done */
|
||||
BITNCF(23), /* unused */
|
||||
BIT(ERR), /* Error */
|
||||
ENDBITS
|
||||
};
|
||||
|
||||
/* Logical console definitions */
|
||||
|
||||
#define LC_NUMBY 128 /* response buffer size */
|
||||
|
@ -205,7 +217,6 @@ uint32 tmr_nicr = 0; /* next interval */
|
|||
uint32 tmr_inc = 0; /* timer increment */
|
||||
int32 tmr_sav = 0; /* timer save */
|
||||
int32 tmr_int = 0; /* interrupt */
|
||||
int32 tmr_use_100hz = 1; /* use 100Hz for timer */
|
||||
int32 clk_tps = 100; /* ticks/second */
|
||||
int32 tmxr_poll = CLK_DELAY * TMXR_MULT; /* term mux poll */
|
||||
int32 tmr_poll = CLK_DELAY; /* pgm timer poll */
|
||||
|
@ -237,7 +248,6 @@ uint16 *rlcs_buf = NULL;
|
|||
|
||||
t_stat tti_svc (UNIT *uptr);
|
||||
t_stat tto_svc (UNIT *uptr);
|
||||
t_stat clk_svc (UNIT *uptr);
|
||||
t_stat tmr_svc (UNIT *uptr);
|
||||
t_stat lc_svc (UNIT *uptr);
|
||||
t_stat rlcs_svc (UNIT *uptr);
|
||||
|
@ -257,9 +267,8 @@ t_stat clk_detach (UNIT *uptr);
|
|||
t_stat tmr_reset (DEVICE *dptr);
|
||||
t_stat rlcs_reset (DEVICE *dptr);
|
||||
t_stat rlcs_attach (UNIT *uptr, CONST char *cptr);
|
||||
int32 icr_rd (t_bool interp);
|
||||
void tmr_incr (uint32 inc);
|
||||
void tmr_sched (void);
|
||||
int32 icr_rd (void);
|
||||
void tmr_sched (uint32 incr);
|
||||
t_stat todr_resync (void);
|
||||
t_stat lc_wr_txdb (int32 data);
|
||||
|
||||
|
@ -349,12 +358,12 @@ DEVICE tto_dev = {
|
|||
|
||||
/* TODR and TMR data structures */
|
||||
|
||||
UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE+UNIT_FIX, sizeof(TOY)), CLK_DELAY };/* 100Hz */
|
||||
UNIT clk_unit = { UDATA (NULL, UNIT_FIX, sizeof(TOY))};
|
||||
|
||||
REG clk_reg[] = {
|
||||
{ DRDATAD (TIME, clk_unit.wait, 24, "initial poll interval"), REG_NZ + PV_LEFT },
|
||||
{ DRDATAD (POLL, tmr_poll, 24, "calibrated poll interval"), REG_NZ + PV_LEFT + REG_HRO },
|
||||
{ DRDATAD (TPS, clk_tps, 8, "ticks per second (100)"), REG_NZ + PV_LEFT },
|
||||
{ DRDATAD (TPS, clk_tps, 8, "ticks per second"), REG_NZ + PV_LEFT },
|
||||
#if defined (SIM_ASYNCH_IO)
|
||||
{ DRDATAD (ASYNCH, sim_asynch_enabled, 1, "asynch I/O enabled flag"), PV_LEFT },
|
||||
{ DRDATAD (LATENCY, sim_asynch_latency, 32, "desired asynch interrupt latency"), PV_LEFT },
|
||||
|
@ -381,16 +390,31 @@ REG tmr_reg[] = {
|
|||
{ FLDATAD (INT, tmr_int, 0, "interrupt request") },
|
||||
{ HRDATA (INCR, tmr_inc, 32), REG_HIDDEN },
|
||||
{ HRDATA (SAVE, tmr_sav, 32), REG_HIDDEN },
|
||||
{ FLDATA (USE100HZ, tmr_use_100hz, 0), REG_HIDDEN },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
#define TMR_DB_REG 0x01 /* Register Access */
|
||||
#define TMR_DB_TICK 0x02 /* Ticks */
|
||||
#define TMR_DB_SCHED 0x04 /* Scheduling */
|
||||
#define TMR_DB_INT 0x08 /* Interrupts */
|
||||
#define TMR_DB_TODR 0x10 /* TODR */
|
||||
|
||||
DEBTAB tmr_deb[] = {
|
||||
{ "REG", TMR_DB_REG, "Register Access"},
|
||||
{ "TICK", TMR_DB_TICK, "Ticks"},
|
||||
{ "SCHED", TMR_DB_SCHED, "Ticks"},
|
||||
{ "INT", TMR_DB_INT, "Interrupts"},
|
||||
{ "TODR", TMR_DB_TODR, "TODR activities"},
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
DEVICE tmr_dev = {
|
||||
"TMR", &tmr_unit, tmr_reg, NULL,
|
||||
1, 0, 0, 0, 0, 0,
|
||||
NULL, NULL, &tmr_reset,
|
||||
NULL, NULL, NULL,
|
||||
NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL, DEV_DEBUG, 0,
|
||||
tmr_deb, NULL, NULL, NULL, NULL, NULL,
|
||||
&tmr_description
|
||||
};
|
||||
|
||||
|
@ -444,10 +468,11 @@ void rxcs_wr (int32 data)
|
|||
{
|
||||
if ((data & CSR_IE) == 0)
|
||||
tti_int = 0;
|
||||
else if ((tti_csr & (CSR_DONE + CSR_IE)) == CSR_DONE)
|
||||
tti_int = 1;
|
||||
else {
|
||||
if ((tti_csr & (CSR_DONE + CSR_IE)) == CSR_DONE)
|
||||
tti_int = 1;
|
||||
}
|
||||
tti_csr = (tti_csr & ~RXCS_WR) | (data & RXCS_WR);
|
||||
return;
|
||||
}
|
||||
|
||||
int32 rxdb_rd (void)
|
||||
|
@ -500,10 +525,10 @@ if (data & TXCS_WMN) { /* Updating enable m
|
|||
}
|
||||
if ((tto_csr & CSR_IE) == 0)
|
||||
tto_int = 0;
|
||||
else
|
||||
else {
|
||||
if ((tto_csr & CSR_DONE) == CSR_DONE)
|
||||
tto_int = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void txdb_wr (int32 data)
|
||||
|
@ -517,7 +542,6 @@ if ((dest >= ID_CT) && (dest <= ID_LC)) { /* valid line? */
|
|||
sim_activate (&tto_unit[dest],
|
||||
((dest == ID_LC) && (data == LC_FNCBT)) ? 0 : tto_unit[dest].wait);/* activate unit */
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int32 stxcs_rd (void)
|
||||
|
@ -591,7 +615,7 @@ int32 line = uptr - tti_dev.units;
|
|||
switch (line) {
|
||||
|
||||
case ID_CT: /* console terminal */
|
||||
sim_clock_coschedule_tmr (uptr, TMR_CLK, TMXR_MULT);/* continue poll */
|
||||
sim_clock_coschedule (uptr, TMXR_MULT); /* continue poll */
|
||||
if ((tti_csr & CSR_DONE) && /* input still pending and < 500ms? */
|
||||
((sim_os_msec () - tti_buftime) < 500))
|
||||
return SCPE_OK;
|
||||
|
@ -631,7 +655,7 @@ tmxr_set_console_units (tti_unit, tto_unit);
|
|||
tti_buf = 0;
|
||||
tti_csr = 0;
|
||||
tti_int = 0;
|
||||
sim_activate_abs (&tti_unit[ID_CT], KBD_WAIT (tti_unit[ID_CT].wait, tmr_poll));
|
||||
sim_activate (&tti_unit[ID_CT], KBD_WAIT (tti_unit[ID_CT].wait, tmr_poll));
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
@ -716,162 +740,143 @@ return "console terminal output";
|
|||
|
||||
The architected VAX timer, which increments at 1Mhz, cannot be
|
||||
accurately simulated due to the overhead that would be required
|
||||
for 1M clock events per second. Instead, a hidden calibrated
|
||||
100Hz timer is run (because that's what VMS expects), and a
|
||||
hack is used for the interval timer.
|
||||
|
||||
When the timer is started, the timer interval is inspected.
|
||||
|
||||
if the interval is >= 10msec, then the 100Hz timer drives the
|
||||
next interval
|
||||
if the interval is < 10mec, then count instructions
|
||||
for 1M clock events per second. Instead 1Mhz intervals are
|
||||
derived from the calibrated instruction execution rate.
|
||||
|
||||
If the interval register is read, then its value between events
|
||||
is interpolated using the current instruction count versus the
|
||||
count when the most recent event started, the result is scaled
|
||||
to the calibrated system clock, unless the interval being timed
|
||||
is less than a calibrated system clock tick (or the calibrated
|
||||
clock is running very slowly) at which time the result will be
|
||||
the elapsed instruction count.
|
||||
is interpolated relative to the elapsed instruction count.
|
||||
*/
|
||||
|
||||
int32 iccs_rd (void)
|
||||
{
|
||||
sim_debug_bits_hdr (TMR_DB_REG, &tmr_dev, "iccs_rd()", tmr_iccs_bits, tmr_iccs, tmr_iccs, TRUE);
|
||||
return tmr_iccs & TMR_CSR_RD;
|
||||
}
|
||||
|
||||
void iccs_wr (int32 val)
|
||||
{
|
||||
sim_debug_bits_hdr (TMR_DB_REG, &tmr_dev, "iccs_wr()", tmr_iccs_bits, tmr_iccs, val, TRUE);
|
||||
if ((val & TMR_CSR_RUN) == 0) { /* clearing run? */
|
||||
sim_cancel (&tmr_unit); /* cancel timer */
|
||||
tmr_use_100hz = 0;
|
||||
if (tmr_iccs & TMR_CSR_RUN) /* run 1 -> 0? */
|
||||
tmr_icr = icr_rd (TRUE); /* update itr */
|
||||
if (tmr_iccs & TMR_CSR_RUN) { /* run 1 -> 0? */
|
||||
tmr_icr = icr_rd (); /* update itr */
|
||||
sim_rtcn_calb (0, TMR_CLK); /* stop timer */
|
||||
}
|
||||
}
|
||||
if (val & CSR_DONE) /* Interrupt Acked? */
|
||||
sim_rtcn_tick_ack (20, TMR_CLK); /* Let timers know */
|
||||
tmr_iccs = tmr_iccs & ~(val & TMR_CSR_W1C); /* W1C csr */
|
||||
tmr_iccs = (tmr_iccs & ~TMR_CSR_WR) | /* new r/w */
|
||||
(val & TMR_CSR_WR);
|
||||
if (val & TMR_CSR_XFR) tmr_icr = tmr_nicr; /* xfr set? */
|
||||
if (val & TMR_CSR_XFR) /* xfr set? */
|
||||
tmr_icr = tmr_nicr;
|
||||
if (val & TMR_CSR_RUN) { /* run? */
|
||||
if (val & TMR_CSR_XFR) /* new tir? */
|
||||
sim_cancel (&tmr_unit); /* stop prev */
|
||||
if (!sim_is_active (&tmr_unit)) /* not running? */
|
||||
tmr_sched (); /* activate */
|
||||
if (!sim_is_active (&tmr_unit)) { /* not running? */
|
||||
sim_rtcn_init_unit (&tmr_unit, CLK_DELAY, TMR_CLK); /* init timer */
|
||||
tmr_sched (tmr_icr); /* activate */
|
||||
}
|
||||
}
|
||||
else if (val & TMR_CSR_SGL) { /* single step? */
|
||||
tmr_incr (1); /* incr tmr */
|
||||
if (tmr_icr == 0) /* if ovflo, */
|
||||
tmr_icr = tmr_nicr; /* reload tir */
|
||||
else {
|
||||
if (val & TMR_CSR_XFR) /* xfr set? */
|
||||
tmr_icr = tmr_nicr;
|
||||
if (val & TMR_CSR_SGL) { /* single step? */
|
||||
tmr_icr = tmr_icr + 1; /* incr tmr */
|
||||
if (tmr_icr == 0) { /* if ovflo, */
|
||||
if (tmr_iccs & TMR_CSR_DON) /* done? set err */
|
||||
tmr_iccs = tmr_iccs | TMR_CSR_ERR;
|
||||
else
|
||||
tmr_iccs = tmr_iccs | TMR_CSR_DON; /* set done */
|
||||
if (tmr_iccs & TMR_CSR_IE) { /* ie? */
|
||||
tmr_int = 1; /* set int req */
|
||||
sim_debug (TMR_DB_INT, &tmr_dev, "tmr_incr() - INT=1\n");
|
||||
}
|
||||
tmr_icr = tmr_nicr; /* reload tir */
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((tmr_iccs & (TMR_CSR_DON | TMR_CSR_IE)) != /* update int */
|
||||
(TMR_CSR_DON | TMR_CSR_IE))
|
||||
tmr_int = 0;
|
||||
return;
|
||||
(TMR_CSR_DON | TMR_CSR_IE)) {
|
||||
if (tmr_int) {
|
||||
tmr_int = 0;
|
||||
sim_debug (TMR_DB_INT, &tmr_dev, "iccs_wr() - INT=0\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32 icr_rd (t_bool interp)
|
||||
int32 icr_rd (void)
|
||||
{
|
||||
uint32 delta;
|
||||
int32 result;
|
||||
|
||||
if (interp || (tmr_iccs & TMR_CSR_RUN)) { /* interp, running? */
|
||||
delta = sim_grtime () - tmr_sav; /* delta inst */
|
||||
if (tmr_use_100hz && (tmr_poll > TMR_INC)) /* scale large int */
|
||||
delta = (uint32) ((((double) delta) * TMR_INC) / tmr_poll);
|
||||
if (delta >= tmr_inc)
|
||||
delta = tmr_inc - 1;
|
||||
return tmr_icr + delta;
|
||||
if (tmr_iccs & TMR_CSR_RUN) { /* running? */
|
||||
uint32 delta = sim_grtime() - tmr_sav;
|
||||
result = (int32)(tmr_nicr + (uint32)((1000000.0 * delta) / sim_timer_inst_per_sec ()));
|
||||
}
|
||||
return tmr_icr;
|
||||
else
|
||||
result = (int32)tmr_icr;
|
||||
sim_debug (TMR_DB_REG, &tmr_dev, "icr_rd() = 0x%08X%s\n", result, (tmr_iccs & TMR_CSR_RUN) ? " - interpolated" : "");
|
||||
return result;
|
||||
}
|
||||
|
||||
int32 nicr_rd (void)
|
||||
{
|
||||
sim_debug (TMR_DB_REG, &tmr_dev, "nicr_rd() = 0x%08X\n", tmr_nicr);
|
||||
return tmr_nicr;
|
||||
}
|
||||
|
||||
void nicr_wr (int32 val)
|
||||
{
|
||||
sim_debug (TMR_DB_REG, &tmr_dev, "nicr_wr(0x%08X)\n", val);
|
||||
tmr_nicr = val;
|
||||
}
|
||||
|
||||
/* 100Hz base clock unit service */
|
||||
|
||||
t_stat clk_svc (UNIT *uptr)
|
||||
{
|
||||
tmr_poll = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */
|
||||
sim_activate_after (&clk_unit, 1000000/clk_tps); /* reactivate unit */
|
||||
tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */
|
||||
AIO_SET_INTERRUPT_LATENCY(tmr_poll*clk_tps); /* set interrrupt latency */
|
||||
if ((tmr_iccs & TMR_CSR_RUN) && tmr_use_100hz) /* timer on, std intvl? */
|
||||
tmr_incr (TMR_INC); /* do timer service */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Interval timer unit service */
|
||||
|
||||
t_stat tmr_svc (UNIT *uptr)
|
||||
{
|
||||
tmr_incr (tmr_inc); /* incr timer */
|
||||
sim_debug (TMR_DB_TICK, &tmr_dev, "tmr_svc()\n");
|
||||
tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */
|
||||
if (tmr_iccs & TMR_CSR_DON) /* done? set err */
|
||||
tmr_iccs = tmr_iccs | TMR_CSR_ERR;
|
||||
else
|
||||
tmr_iccs = tmr_iccs | TMR_CSR_DON; /* set done */
|
||||
if (tmr_iccs & TMR_CSR_RUN) /* run? */
|
||||
tmr_sched (tmr_nicr); /* reactivate */
|
||||
if (tmr_iccs & TMR_CSR_IE) { /* ie? set int req */
|
||||
tmr_int = 1;
|
||||
sim_debug (TMR_DB_INT, &tmr_dev, "tmr_svc() - INT=1\n");
|
||||
}
|
||||
else
|
||||
tmr_int = 0;
|
||||
AIO_SET_INTERRUPT_LATENCY(tmr_poll*clk_tps); /* set interrrupt latency */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Timer increment */
|
||||
|
||||
void tmr_incr (uint32 inc)
|
||||
{
|
||||
uint32 new_icr = (tmr_icr + inc) & LMASK; /* add incr */
|
||||
|
||||
if (new_icr < tmr_icr) { /* ovflo? */
|
||||
tmr_icr = 0; /* now 0 */
|
||||
if (tmr_iccs & TMR_CSR_DON) /* done? set err */
|
||||
tmr_iccs = tmr_iccs | TMR_CSR_ERR;
|
||||
else tmr_iccs = tmr_iccs | TMR_CSR_DON; /* set done */
|
||||
if (tmr_iccs & TMR_CSR_RUN) { /* run? */
|
||||
tmr_icr = tmr_nicr; /* reload */
|
||||
tmr_sched (); /* reactivate */
|
||||
}
|
||||
if (tmr_iccs & TMR_CSR_IE) /* ie? set int req */
|
||||
tmr_int = 1;
|
||||
else tmr_int = 0;
|
||||
}
|
||||
else {
|
||||
tmr_icr = new_icr; /* no, update icr */
|
||||
if (tmr_iccs & TMR_CSR_RUN) /* still running? */
|
||||
tmr_sched (); /* reactivate */
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Timer scheduling */
|
||||
|
||||
void tmr_sched (void)
|
||||
void tmr_sched (uint32 nicr)
|
||||
{
|
||||
tmr_sav = sim_grtime (); /* save intvl base */
|
||||
tmr_inc = (~tmr_icr + 1); /* inc = interval */
|
||||
if (tmr_inc == 0) tmr_inc = 1;
|
||||
if (tmr_inc < TMR_INC) { /* 100Hz multiple? */
|
||||
sim_activate (&tmr_unit, tmr_inc); /* schedule timer */
|
||||
tmr_use_100hz = 0;
|
||||
}
|
||||
else tmr_use_100hz = 1; /* let clk handle */
|
||||
return;
|
||||
uint32 usecs = (nicr) ? (~nicr + 1) : 0xFFFFFFFF;
|
||||
|
||||
clk_tps = 1000000 / usecs;
|
||||
|
||||
sim_debug (TMR_DB_SCHED, &tmr_dev, "tmr_sched(nicr=0x%08X-usecs=0x%08X) - tps=%d\n", nicr, usecs, clk_tps);
|
||||
tmr_poll = sim_rtcn_calb (clk_tps, TMR_CLK);
|
||||
if (SCPE_OK == sim_activate_after (&tmr_unit, usecs))
|
||||
tmr_sav = sim_grtime(); /* Save interval base time */
|
||||
}
|
||||
|
||||
/* 100Hz clock reset */
|
||||
/* 100Hz TODR reset */
|
||||
|
||||
t_stat clk_reset (DEVICE *dptr)
|
||||
{
|
||||
tmr_poll = sim_rtcn_init_unit (&clk_unit, clk_unit.wait, TMR_CLK);/* init 100Hz timer */
|
||||
sim_activate_after (&clk_unit, 1000000/clk_tps); /* activate 100Hz unit */
|
||||
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 ();
|
||||
}
|
||||
todr_resync ();
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
@ -970,13 +975,12 @@ return r;
|
|||
|
||||
t_stat tmr_reset (DEVICE *dptr)
|
||||
{
|
||||
tmr_poll = sim_rtcn_init_unit (&tmr_unit, CLK_DELAY, TMR_CLK); /* init timer */
|
||||
tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */
|
||||
tmr_iccs = 0;
|
||||
tmr_icr = 0;
|
||||
tmr_nicr = 0;
|
||||
tmr_int = 0;
|
||||
tmr_use_100hz = 1;
|
||||
sim_cancel (&tmr_unit); /* cancel timer */
|
||||
todr_resync (); /* resync TODR */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
|
@ -1220,7 +1224,8 @@ switch (rlcs_state) {
|
|||
rlcs_csr = rlcs_csr | RLCS_ERR; /* set master error bit */
|
||||
if (rlcs_bcnt > 0) /* transfer in progress? */
|
||||
rlcs_csr = rlcs_csr & ~RLCS_DRDY;
|
||||
else rlcs_csr = rlcs_csr | RLCS_DRDY;
|
||||
else
|
||||
rlcs_csr = rlcs_csr | RLCS_DRDY;
|
||||
cso_buf = rlcs_csr;
|
||||
rlcs_sts_reg = RL_MP; /* MP on next read */
|
||||
break;
|
||||
|
@ -1228,7 +1233,8 @@ switch (rlcs_state) {
|
|||
case RL_MP:
|
||||
if ((uptr->flags & UNIT_ATT) == 0) /* update status */
|
||||
rlcs_mp = RLDS_UNATT;
|
||||
else rlcs_mp = RLDS_ATT;
|
||||
else
|
||||
rlcs_mp = RLDS_ATT;
|
||||
cso_buf = rlcs_mp;
|
||||
rlcs_sts_reg = RL_CSR; /* MP on next read */
|
||||
break;
|
||||
|
|
Loading…
Add table
Reference in a new issue