From 76103cf760c1ef6a153186b95c58c3e2cbbfb255 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Fri, 16 Dec 2016 18:32:26 -0800 Subject: [PATCH] VAX730, VAX750, VAX8600: Update Interval Timer and TODR to align with VAX780 --- VAX/vax730_stddev.c | 272 +++++++++++++++++++++++++------------------- VAX/vax750_stddev.c | 210 +++++++++++++++------------------- VAX/vax780_stddev.c | 38 +++---- VAX/vax860_stddev.c | 238 +++++++++++++++++++------------------- 4 files changed, 384 insertions(+), 374 deletions(-) diff --git a/VAX/vax730_stddev.c b/VAX/vax730_stddev.c index 5926e014..eb94eebb 100644 --- a/VAX/vax730_stddev.c +++ b/VAX/vax730_stddev.c @@ -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; diff --git a/VAX/vax750_stddev.c b/VAX/vax750_stddev.c index d3685250..dd3c6d65 100644 --- a/VAX/vax750_stddev.c +++ b/VAX/vax750_stddev.c @@ -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 */ diff --git a/VAX/vax780_stddev.c b/VAX/vax780_stddev.c index 290f87fe..28cbbf05 100644 --- a/VAX/vax780_stddev.c +++ b/VAX/vax780_stddev.c @@ -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 */ diff --git a/VAX/vax860_stddev.c b/VAX/vax860_stddev.c index 4d2242fa..8e84b53b 100644 --- a/VAX/vax860_stddev.c +++ b/VAX/vax860_stddev.c @@ -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;