VAX780: Fix Interval Timer logic

- Previous changes made to support 32V's 60HZ clock tick introduced changes
  which didn't properly handle increments and interrupt generation while single
  stepping the timer.

- The icr_rd routine returned an incorrect value when interpolation was
  necessary due to a missing cast when converting from double to uint32.

- Properly start the timer from the current state of the interval count register
  when the timer was previously stopped.
This commit is contained in:
Mark Pizzolato 2016-06-20 15:56:19 -07:00
parent b935a2dafc
commit c5d5a9dfbf
3 changed files with 123 additions and 31 deletions

View file

@ -134,6 +134,18 @@ static BITFIELD tx_buf_bits[] = {
#define CLK_DELAY 5000 /* 100 Hz */ #define CLK_DELAY 5000 /* 100 Hz */
#define TMXR_MULT 1 /* 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 */ /* TU58 definitions */
#define UNIT_V_WLK (UNIT_V_UF) /* write locked */ #define UNIT_V_WLK (UNIT_V_UF) /* write locked */
@ -301,7 +313,7 @@ DEVICE clk_dev = {
UNIT tmr_unit = { UDATA (&tmr_svc, 0, 0) }; /* timer */ UNIT tmr_unit = { UDATA (&tmr_svc, 0, 0) }; /* timer */
REG tmr_reg[] = { REG tmr_reg[] = {
{ HRDATAD (ICCS, tmr_iccs, 32, "interval timer control and status") }, { HRDATADF (ICCS, tmr_iccs, 32, "interval timer control and status", tmr_iccs_bits) },
{ HRDATAD (ICR, tmr_icr, 32, "interval count register") }, { HRDATAD (ICR, tmr_icr, 32, "interval count register") },
{ HRDATAD (NICR, tmr_nicr, 32, "next interval count register") }, { HRDATAD (NICR, tmr_nicr, 32, "next interval count register") },
{ FLDATAD (INT, tmr_int, 0, "interrupt request") }, { FLDATAD (INT, tmr_int, 0, "interrupt request") },
@ -311,12 +323,26 @@ REG tmr_reg[] = {
{ NULL } { 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 */
DEBTAB tmr_deb[] = {
{ "REG", TMR_DB_REG, "Register Access"},
{ "TICK", TMR_DB_TICK, "Ticks"},
{ "SCHED", TMR_DB_SCHED, "Ticks"},
{ "INT", TMR_DB_INT, "Interrupts"},
{ NULL, 0 }
};
DEVICE tmr_dev = { DEVICE tmr_dev = {
"TMR", &tmr_unit, tmr_reg, NULL, "TMR", &tmr_unit, tmr_reg, NULL,
1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
NULL, NULL, &tmr_reset, NULL, NULL, &tmr_reset,
NULL, NULL, NULL, 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 &tmr_description
}; };
@ -627,11 +653,13 @@ return "console terminal output";
int32 iccs_rd (void) int32 iccs_rd (void)
{ {
sim_debug (TMR_DB_REG, &tmr_dev, "iccs_rd() = 0x%08X\n", tmr_iccs & TMR_CSR_RD);
return tmr_iccs & TMR_CSR_RD; return tmr_iccs & TMR_CSR_RD;
} }
void iccs_wr (int32 val) void iccs_wr (int32 val)
{ {
sim_debug_bits_hdr (TMR_DB_REG, &tmr_dev, "iccs_wr()", tmr_iccs_bits, val, val, TRUE);
if ((val & TMR_CSR_RUN) == 0) { /* clearing run? */ if ((val & TMR_CSR_RUN) == 0) { /* clearing run? */
sim_cancel (&tmr_unit); /* cancel timer */ sim_cancel (&tmr_unit); /* cancel timer */
tmr_use_100hz = 0; tmr_use_100hz = 0;
@ -654,8 +682,12 @@ else if (val & TMR_CSR_SGL) { /* single step? */
tmr_icr = tmr_nicr; /* reload tir */ tmr_icr = tmr_nicr; /* reload tir */
} }
if ((tmr_iccs & (TMR_CSR_DON | TMR_CSR_IE)) != /* update int */ if ((tmr_iccs & (TMR_CSR_DON | TMR_CSR_IE)) != /* update int */
(TMR_CSR_DON | TMR_CSR_IE)) (TMR_CSR_DON | TMR_CSR_IE)) {
if (tmr_int) {
tmr_int = 0; tmr_int = 0;
sim_debug (TMR_DB_INT, &tmr_dev, "iccs_wr() - INT=0\n");
}
}
return; return;
} }
@ -669,18 +701,22 @@ if (interp || (tmr_iccs & TMR_CSR_RUN)) { /* interp, running? */
delta = (uint32) ((((double) delta) * TMR_INC) / tmr_poll); delta = (uint32) ((((double) delta) * TMR_INC) / tmr_poll);
if (delta >= tmr_inc) if (delta >= tmr_inc)
delta = tmr_inc - 1; delta = tmr_inc - 1;
sim_debug (TMR_DB_REG, &tmr_dev, "icr_rd() = 0x%08X\n", tmr_icr + delta);
return tmr_icr + delta; return tmr_icr + delta;
} }
sim_debug (TMR_DB_REG, &tmr_dev, "icr_rd() = 0x%08X\n", tmr_icr);
return tmr_icr; return tmr_icr;
} }
int32 nicr_rd (void) int32 nicr_rd (void)
{ {
sim_debug (TMR_DB_REG, &tmr_dev, "nicr_rd() = 0x%08X\n", tmr_nicr);
return tmr_nicr; return tmr_nicr;
} }
void nicr_wr (int32 val) void nicr_wr (int32 val)
{ {
sim_debug (TMR_DB_REG, &tmr_dev, "nicr_wr(0x%08X)\n", val);
tmr_nicr = val; tmr_nicr = val;
} }
@ -688,6 +724,7 @@ tmr_nicr = val;
t_stat clk_svc (UNIT *uptr) 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 */ tmr_poll = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */
sim_activate_after (uptr, 1000000/clk_tps); /* reactivate unit */ sim_activate_after (uptr, 1000000/clk_tps); /* reactivate unit */
tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */ tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */
@ -701,6 +738,7 @@ return SCPE_OK;
t_stat tmr_svc (UNIT *uptr) t_stat tmr_svc (UNIT *uptr)
{ {
sim_debug (TMR_DB_TICK, &tmr_dev, "tmr_svc()\n");
tmr_incr (tmr_inc); /* incr timer */ tmr_incr (tmr_inc); /* incr timer */
return SCPE_OK; return SCPE_OK;
} }
@ -720,8 +758,10 @@ if (new_icr < tmr_icr) { /* ovflo? */
tmr_icr = tmr_nicr; /* reload */ tmr_icr = tmr_nicr; /* reload */
tmr_sched (); /* reactivate */ tmr_sched (); /* reactivate */
} }
if (tmr_iccs & TMR_CSR_IE) /* ie? set int req */ if (tmr_iccs & TMR_CSR_IE) { /* ie? set int req */
tmr_int = 1; tmr_int = 1;
sim_debug (TMR_DB_INT, &tmr_dev, "tmr_incr() - INT=1\n");
}
else tmr_int = 0; else tmr_int = 0;
} }
else { else {
@ -739,6 +779,7 @@ void tmr_sched (void)
tmr_sav = sim_grtime (); /* save intvl base */ tmr_sav = sim_grtime (); /* save intvl base */
tmr_inc = (~tmr_icr + 1); /* inc = interval */ tmr_inc = (~tmr_icr + 1); /* inc = interval */
if (tmr_inc == 0) tmr_inc = 1; 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? */ if (tmr_inc < TMR_INC) { /* 100Hz multiple? */
sim_activate (&tmr_unit, tmr_inc); /* schedule timer */ sim_activate (&tmr_unit, tmr_inc); /* schedule timer */
tmr_use_100hz = 0; tmr_use_100hz = 0;

View file

@ -137,6 +137,18 @@
#define CLK_DELAY 5000 /* 100 Hz */ #define CLK_DELAY 5000 /* 100 Hz */
#define TMXR_MULT 1 /* 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
};
/* Floppy definitions */ /* Floppy definitions */
#define FL_NUMTR 77 /* tracks/disk */ #define FL_NUMTR 77 /* tracks/disk */
@ -347,7 +359,7 @@ DEVICE clk_dev = {
UNIT tmr_unit = { UDATA (&tmr_svc, 0, 0) }; /* timer */ UNIT tmr_unit = { UDATA (&tmr_svc, 0, 0) }; /* timer */
REG tmr_reg[] = { REG tmr_reg[] = {
{ HRDATAD (ICCS, tmr_iccs, 32, "interval timer control and status") }, { HRDATADF (ICCS, tmr_iccs, 32, "interval timer control and status", tmr_iccs_bits) },
{ HRDATAD (ICR, tmr_icr, 32, "interval count register") }, { HRDATAD (ICR, tmr_icr, 32, "interval count register") },
{ HRDATAD (NICR, tmr_nicr, 32, "next interval count register") }, { HRDATAD (NICR, tmr_nicr, 32, "next interval count register") },
{ FLDATAD (INT, tmr_int, 0, "interrupt request") }, { FLDATAD (INT, tmr_int, 0, "interrupt request") },
@ -356,12 +368,26 @@ REG tmr_reg[] = {
{ NULL } { 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 */
DEBTAB tmr_deb[] = {
{ "REG", TMR_DB_REG, "Register Access"},
{ "TICK", TMR_DB_TICK, "Ticks"},
{ "SCHED", TMR_DB_SCHED, "Ticks"},
{ "INT", TMR_DB_INT, "Interrupts"},
{ NULL, 0 }
};
DEVICE tmr_dev = { DEVICE tmr_dev = {
"TMR", &tmr_unit, tmr_reg, NULL, "TMR", &tmr_unit, tmr_reg, NULL,
1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
NULL, NULL, &tmr_reset, NULL, NULL, &tmr_reset,
NULL, NULL, NULL, 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 &tmr_description
}; };
@ -585,11 +611,13 @@ return "console terminal output";
int32 iccs_rd (void) 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; return tmr_iccs & TMR_CSR_RD;
} }
void iccs_wr (int32 val) 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? */ if ((val & TMR_CSR_RUN) == 0) { /* clearing run? */
sim_cancel (&tmr_unit); /* cancel timer */ sim_cancel (&tmr_unit); /* cancel timer */
if (tmr_iccs & TMR_CSR_RUN) /* run 1 -> 0? */ if (tmr_iccs & TMR_CSR_RUN) /* run 1 -> 0? */
@ -604,42 +632,59 @@ if (val & TMR_CSR_RUN) { /* run? */
if (val & TMR_CSR_XFR) /* new tir? */ if (val & TMR_CSR_XFR) /* new tir? */
sim_cancel (&tmr_unit); /* stop prev */ sim_cancel (&tmr_unit); /* stop prev */
if (!sim_is_active (&tmr_unit)) /* not running? */ if (!sim_is_active (&tmr_unit)) /* not running? */
tmr_sched (tmr_nicr); /* activate */ tmr_sched (tmr_icr); /* activate */
} }
else { else {
if (val & TMR_CSR_XFR) /* xfr set? */ if (val & TMR_CSR_XFR) /* xfr set? */
tmr_icr = tmr_nicr; tmr_icr = tmr_nicr;
if (val & TMR_CSR_SGL) { /* single step? */ if (val & TMR_CSR_SGL) { /* single step? */
tmr_icr = tmr_inc + 1; /* incr tmr */ tmr_icr = tmr_icr + 1; /* incr tmr */
if (tmr_icr == 0) { /* if ovflo, */ if (tmr_icr == 0) { /* if ovflo, */
if (tmr_iccs & TMR_CSR_IE) /* ie? */ 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 */ tmr_int = 1; /* set int req */
sim_debug (TMR_DB_INT, &tmr_dev, "tmr_incr() - INT=1\n");
}
tmr_icr = tmr_nicr; /* reload tir */ tmr_icr = tmr_nicr; /* reload tir */
} }
} }
} }
if ((tmr_iccs & (TMR_CSR_DON | TMR_CSR_IE)) != /* update int */ if ((tmr_iccs & (TMR_CSR_DON | TMR_CSR_IE)) != /* update int */
(TMR_CSR_DON | TMR_CSR_IE)) (TMR_CSR_DON | TMR_CSR_IE)) {
if (tmr_int) {
tmr_int = 0; tmr_int = 0;
sim_debug (TMR_DB_INT, &tmr_dev, "iccs_wr() - INT=0\n");
}
}
return; return;
} }
int32 icr_rd () int32 icr_rd ()
{ {
uint32 delta = sim_grtime() - tmr_sav; int32 result;
if (tmr_iccs & TMR_CSR_RUN) /* running? */ if (tmr_iccs & TMR_CSR_RUN) { /* running? */
return (int32)(tmr_nicr + ((1000000.0 * delta) / sim_timer_inst_per_sec ())); uint32 delta = sim_grtime() - tmr_sav;
return (int32)tmr_icr; result = (int32)(tmr_nicr + (uint32)((1000000.0 * delta) / sim_timer_inst_per_sec ()));
}
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) int32 nicr_rd (void)
{ {
sim_debug (TMR_DB_REG, &tmr_dev, "nicr_rd() = 0x%08X\n", tmr_nicr);
return tmr_nicr; return tmr_nicr;
} }
void nicr_wr (int32 val) void nicr_wr (int32 val)
{ {
sim_debug (TMR_DB_REG, &tmr_dev, "nicr_wr(0x%08X)\n", val);
tmr_nicr = val; tmr_nicr = val;
} }
@ -658,14 +703,17 @@ return SCPE_OK;
t_stat tmr_svc (UNIT *uptr) t_stat tmr_svc (UNIT *uptr)
{ {
sim_debug (TMR_DB_TICK, &tmr_dev, "tmr_svc()\n");
if (tmr_iccs & TMR_CSR_DON) /* done? set err */ if (tmr_iccs & TMR_CSR_DON) /* done? set err */
tmr_iccs = tmr_iccs | TMR_CSR_ERR; tmr_iccs = tmr_iccs | TMR_CSR_ERR;
else else
tmr_iccs = tmr_iccs | TMR_CSR_DON; /* set done */ tmr_iccs = tmr_iccs | TMR_CSR_DON; /* set done */
if (tmr_iccs & TMR_CSR_RUN) /* run? */ if (tmr_iccs & TMR_CSR_RUN) /* run? */
tmr_sched (tmr_nicr); /* reactivate */ tmr_sched (tmr_nicr); /* reactivate */
if (tmr_iccs & TMR_CSR_IE) /* ie? set int req */ if (tmr_iccs & TMR_CSR_IE) { /* ie? set int req */
tmr_int = 1; tmr_int = 1;
sim_debug (TMR_DB_INT, &tmr_dev, "tmr_svc() - INT=1\n");
}
else else
tmr_int = 0; tmr_int = 0;
return SCPE_OK; return SCPE_OK;
@ -675,8 +723,11 @@ return SCPE_OK;
void tmr_sched (uint32 nicr) void tmr_sched (uint32 nicr)
{ {
sim_activate_after (&tmr_unit, (nicr) ? (~nicr + 1) : 0xFFFFFFFF); uint32 usecs = (nicr) ? (~nicr + 1) : 0xFFFFFFFF;
tmr_sav = sim_grtime();
sim_debug (TMR_DB_SCHED, &tmr_dev, "tmr_sched(0x%08X-0x%08X)\n", nicr, usecs);
if (SCPE_OK == sim_activate_after (&tmr_unit, usecs))
tmr_sav = sim_grtime(); /* Save interval base time */
} }
/* 100Hz clock reset */ /* 100Hz clock reset */

2
scp.c
View file

@ -1986,7 +1986,7 @@ if (*argv[0]) { /* sim name arg? */
if (np == NULL) if (np == NULL)
np = strrchr (nbuf, ']'); /* VMS path separator */ np = strrchr (nbuf, ']'); /* VMS path separator */
if (np != NULL) if (np != NULL)
setenv ("SIM_BIN_NAME", np, 1); /* Publish simulator binary name */ setenv ("SIM_BIN_NAME", np+1, 1); /* Publish simulator binary name */
} }
sim_argv = argv; sim_argv = argv;
cptr = getenv("HOME"); cptr = getenv("HOME");