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 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 */
@ -301,22 +313,36 @@ DEVICE clk_dev = {
UNIT tmr_unit = { UDATA (&tmr_svc, 0, 0) }; /* timer */
REG tmr_reg[] = {
{ HRDATAD (ICCS, tmr_iccs, 32, "interval timer control and status") },
{ HRDATAD (ICR, tmr_icr, 32, "interval count register") },
{ HRDATAD (NICR, tmr_nicr, 32, "next interval count register") },
{ 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 },
{ HRDATADF (ICCS, tmr_iccs, 32, "interval timer control and status", tmr_iccs_bits) },
{ HRDATAD (ICR, tmr_icr, 32, "interval count register") },
{ HRDATAD (NICR, tmr_nicr, 32, "next interval count register") },
{ 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 */
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 = {
"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
};
@ -627,11 +653,13 @@ return "console terminal output";
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;
}
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? */
sim_cancel (&tmr_unit); /* cancel timer */
tmr_use_100hz = 0;
@ -654,8 +682,12 @@ else if (val & TMR_CSR_SGL) { /* single step? */
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;
(TMR_CSR_DON | TMR_CSR_IE)) {
if (tmr_int) {
tmr_int = 0;
sim_debug (TMR_DB_INT, &tmr_dev, "iccs_wr() - INT=0\n");
}
}
return;
}
@ -669,18 +701,22 @@ if (interp || (tmr_iccs & TMR_CSR_RUN)) { /* interp, running? */
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;
}
sim_debug (TMR_DB_REG, &tmr_dev, "icr_rd() = 0x%08X\n", tmr_icr);
return tmr_icr;
}
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;
}
@ -688,6 +724,7 @@ tmr_nicr = val;
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 */
@ -701,6 +738,7 @@ return SCPE_OK;
t_stat tmr_svc (UNIT *uptr)
{
sim_debug (TMR_DB_TICK, &tmr_dev, "tmr_svc()\n");
tmr_incr (tmr_inc); /* incr timer */
return SCPE_OK;
}
@ -720,8 +758,10 @@ if (new_icr < tmr_icr) { /* ovflo? */
tmr_icr = tmr_nicr; /* reload */
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;
sim_debug (TMR_DB_INT, &tmr_dev, "tmr_incr() - INT=1\n");
}
else tmr_int = 0;
}
else {
@ -739,6 +779,7 @@ void tmr_sched (void)
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;

View file

@ -137,6 +137,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
};
/* Floppy definitions */
#define FL_NUMTR 77 /* tracks/disk */
@ -347,21 +359,35 @@ DEVICE clk_dev = {
UNIT tmr_unit = { UDATA (&tmr_svc, 0, 0) }; /* timer */
REG tmr_reg[] = {
{ HRDATAD (ICCS, tmr_iccs, 32, "interval timer control and status") },
{ HRDATAD (ICR, tmr_icr, 32, "interval count register") },
{ HRDATAD (NICR, tmr_nicr, 32, "next interval count register") },
{ FLDATAD (INT, tmr_int, 0, "interrupt request") },
{ HRDATA (INCR, tmr_inc, 32), REG_HIDDEN },
{ HRDATA (SAVE, tmr_sav, 32), REG_HIDDEN },
{ HRDATADF (ICCS, tmr_iccs, 32, "interval timer control and status", tmr_iccs_bits) },
{ HRDATAD (ICR, tmr_icr, 32, "interval count register") },
{ HRDATAD (NICR, tmr_nicr, 32, "next interval count register") },
{ FLDATAD (INT, tmr_int, 0, "interrupt request") },
{ HRDATA (INCR, tmr_inc, 32), REG_HIDDEN },
{ HRDATA (SAVE, tmr_sav, 32), 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 */
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 = {
"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
};
@ -585,11 +611,13 @@ return "console terminal output";
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 */
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? */
sim_cancel (&tmr_unit); /* stop prev */
if (!sim_is_active (&tmr_unit)) /* not running? */
tmr_sched (tmr_nicr); /* activate */
tmr_sched (tmr_icr); /* activate */
}
else {
if (val & TMR_CSR_XFR) /* xfr set? */
tmr_icr = tmr_nicr;
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_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 */
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;
(TMR_CSR_DON | TMR_CSR_IE)) {
if (tmr_int) {
tmr_int = 0;
sim_debug (TMR_DB_INT, &tmr_dev, "iccs_wr() - INT=0\n");
}
}
return;
}
int32 icr_rd ()
{
uint32 delta = sim_grtime() - tmr_sav;
int32 result;
if (tmr_iccs & TMR_CSR_RUN) /* running? */
return (int32)(tmr_nicr + ((1000000.0 * delta) / sim_timer_inst_per_sec ()));
return (int32)tmr_icr;
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 ()));
}
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;
}
@ -658,14 +703,17 @@ return SCPE_OK;
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 */
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 */
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;
return SCPE_OK;
@ -675,8 +723,11 @@ return SCPE_OK;
void tmr_sched (uint32 nicr)
{
sim_activate_after (&tmr_unit, (nicr) ? (~nicr + 1) : 0xFFFFFFFF);
tmr_sav = sim_grtime();
uint32 usecs = (nicr) ? (~nicr + 1) : 0xFFFFFFFF;
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 */

2
scp.c
View file

@ -1986,7 +1986,7 @@ if (*argv[0]) { /* sim name arg? */
if (np == NULL)
np = strrchr (nbuf, ']'); /* VMS path separator */
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;
cptr = getenv("HOME");