diff --git a/3B2/3b2_cpu.c b/3B2/3b2_cpu.c index 4eacb2ed..29bb2f90 100644 --- a/3B2/3b2_cpu.c +++ b/3B2/3b2_cpu.c @@ -48,6 +48,9 @@ volatile uint32 abort_context; /* Pointer to the last decoded instruction */ instr *cpu_instr; +/* The instruction to use if there is no history storage */ +instr inst; + /* Circular buffer of instructions */ instr *INST = NULL; uint32 cpu_hist_size = 0; @@ -1311,6 +1314,10 @@ t_bool cpu_on_interrupt(uint8 ipl) uint32 new_pcbp; uint16 id = ipl; /* TODO: Does this need to be uint16? */ + sim_debug(IRQ_MSG, &cpu_dev, + "[%08x] [cpu_on_interrupt] ipl=%d\n", + R[NUM_PC], ipl); + /* * "If a nonmaskable interrupt request is received, an auto-vector * interrupt acknowledge cycle is performed (as if an autovector @@ -1368,8 +1375,6 @@ t_stat sim_instr(void) uint32 width, offset; t_uint64 mask; - instr inst; - operand *src1, *src2, *src3, *dst; stop_reason = 0; diff --git a/3B2/3b2_defs.h b/3B2/3b2_defs.h index 4d1fc795..10f1f848 100644 --- a/3B2/3b2_defs.h +++ b/3B2/3b2_defs.h @@ -295,8 +295,10 @@ noret __libc_longjmp (jmp_buf buf, int val); #define TMR_CLK 0 /* The clock responsible for IPL 15 interrupts */ #define TMR_TOD 1 /* The Time-of-Day clock */ -#define TPS_CLK 100 -#define TPS_TOD 10 +#define CLK_MIN_TICKS 500 /* No fewer than 500 sim steps between ticks */ + +#define TPS_CLK 100 /* 100 ticks per second */ +#define TPS_TOD 10 /* 10 ticks per second */ /* TIMING SECTION */ @@ -304,7 +306,7 @@ noret __libc_longjmp (jmp_buf buf, int val); /* Calculate delays (in simulator steps) for times */ /* System clock runs at 10MHz; 100ns period. */ -#define US_PER_INST 0.9 +#define US_PER_INST 1.0 #define INST_PER_MS (1000.0 / US_PER_INST) diff --git a/3B2/3b2_iu.c b/3B2/3b2_iu.c index f5eeaad4..95ec3619 100644 --- a/3B2/3b2_iu.c +++ b/3B2/3b2_iu.c @@ -250,28 +250,6 @@ void iu_txrdy_b_irq() { } } -t_stat iu_reset() -{ - t_stat result; - - result = tti_a_reset(&tti_a_dev); - if (result != SCPE_OK) { - return result; - } - - result = tti_b_reset(&tti_b_dev); - if (result != SCPE_OK) { - return result; - } - - result = iu_timer_reset(&iu_timer_dev); - if (result != SCPE_OK) { - return result; - } - - return SCPE_OK; -} - t_stat tti_a_reset(DEVICE *dptr) { memset(&iu_state, 0, sizeof(IU_STATE)); diff --git a/3B2/3b2_iu.h b/3B2/3b2_iu.h index 5c80806c..ba29bd3a 100644 --- a/3B2/3b2_iu.h +++ b/3B2/3b2_iu.h @@ -180,9 +180,6 @@ typedef struct iu_timer_state { extern IU_PORT iu_port_a; extern IU_PORT iu_port_b; -/* Global reset */ -extern t_stat iu_reset(); - /* Function prototypes */ t_stat tti_a_reset(DEVICE *dptr); t_stat tti_b_reset(DEVICE *dptr); diff --git a/3B2/3b2_sys.c b/3B2/3b2_sys.c index 99799e37..2fa868a1 100644 --- a/3B2/3b2_sys.c +++ b/3B2/3b2_sys.c @@ -76,6 +76,18 @@ const char *sim_stop_messages[] = { "Unimplemented MMU Feature" }; +void full_reset() +{ + cpu_reset(&cpu_dev); + tti_a_reset(&tti_a_dev); + tti_b_reset(&tti_b_dev); + iu_timer_reset(&iu_timer_dev); + timer_reset(&timer_dev); + if_reset(&if_dev); + id_reset(&id_dev); + csr_reset(&csr_dev); +} + t_stat sim_load(FILE *fileref, CONST char *cptr, CONST char *fnam, int flag) { int32 i; diff --git a/3B2/3b2_sys.h b/3B2/3b2_sys.h index 7407e08d..4d575858 100644 --- a/3B2/3b2_sys.h +++ b/3B2/3b2_sys.h @@ -39,6 +39,7 @@ extern REG *sim_PC; extern int32 sim_emax; extern DEVICE *sim_devices[]; +void full_reset(); t_stat sim_load (FILE *fileref, CONST char *cptr, CONST char *fnam, int flag); t_stat parse_sym (CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw); diff --git a/3B2/3b2_sysdev.c b/3B2/3b2_sysdev.c index 94131c8f..c01997a7 100644 --- a/3B2/3b2_sysdev.c +++ b/3B2/3b2_sysdev.c @@ -51,6 +51,8 @@ DEBTAB sys_deb_tab[] = { { NULL, 0 } }; +struct timer_ctr TIMERS[3]; + uint32 *NVRAM = NULL; extern DEVICE cpu_dev; @@ -151,8 +153,7 @@ void csr_write(uint32 pa, uint32 val, size_t size) csr_data &= ~CSRPARE; break; case 0x0b: /* Set System Reset Request */ - iu_reset(); - cpu_reset(&cpu_dev); + full_reset(); cpu_boot(0, &cpu_dev); break; case 0x0f: /* Clear Memory Alignment Fault */ @@ -171,9 +172,32 @@ void csr_write(uint32 pa, uint32 val, size_t size) csr_data &= ~CSRFLOP; break; case 0x23: /* Set Inhibit Timers */ + sim_debug(WRITE_MSG, &csr_dev, + "[%08x] SET INHIBIT TIMERS\n", R[NUM_PC]); csr_data |= CSRITIM; break; case 0x27: /* Clear Inhibit Timers */ + sim_debug(WRITE_MSG, &csr_dev, + "[%08x] CLEAR INHIBIT TIMERS\n", R[NUM_PC]); + + /* A side effect of clearing the timer inhibit bit is to cause + * a simulated "tick" of any active timers. This is a hack to + * make diagnostics pass. This is not 100% accurate, but it + * makes SVR3 and DGMON tests happy. + */ + + if (TIMERS[0].gate && TIMERS[0].enabled) { + TIMERS[0].val = TIMERS[0].divider - 1; + } + + if (TIMERS[1].gate && TIMERS[1].enabled) { + TIMERS[1].val = TIMERS[1].divider - 1; + } + + if (TIMERS[2].gate && TIMERS[2].enabled) { + TIMERS[2].val = TIMERS[2].divider - 1; + } + csr_data &= ~CSRITIM; break; case 0x2b: /* Set Inhibit Faults */ @@ -368,8 +392,6 @@ void nvram_write(uint32 pa, uint32 val, size_t size) * */ -struct timer_ctr TIMERS[3]; - /* * The three timers, (A, B, C) run at different * programmatially controlled frequencies, so each must be @@ -383,6 +405,8 @@ UNIT timer_unit[] = { { NULL } }; +UNIT *timer_clk_unit = &timer_unit[1]; + REG timer_reg[] = { { HRDATAD(DIVA, TIMERS[0].divider, 16, "Divider A") }, { HRDATAD(STA, TIMERS[0].mode, 16, "Mode A") }, @@ -401,27 +425,11 @@ DEVICE timer_dev = { DEV_DEBUG, 0, sys_deb_tab }; -#define TIMER_STP_US 10 /* 10 us delay per timer step */ +#define TIMER_STP_US 10 /* 10 us delay per timer step */ #define tmrnum u3 #define tmr up7 -#define DECR_STEPS 400 -/* - * This is a hack to make diagnostics pass. If read immediately after - * being set, a counter should always return the initial value. If a - * certain number of steps have passed, it should have decremented a - * little bit, so we return a value one less than the initial value. - * This is not 100% accurate, but it makes SVR3 and DGMON tests happy. - */ -static SIM_INLINE uint16 timer_current_val(struct timer_ctr *ctr) -{ - if ((sim_gtime() - ctr->stime) > DECR_STEPS) { - return ctr->divider - 1; - } else { - return ctr->divider; - } -} t_stat timer_reset(DEVICE *dptr) { int32 i, t; @@ -437,8 +445,8 @@ t_stat timer_reset(DEVICE *dptr) { TIMERS[1].gate = 1; if (!sim_is_running) { - t = sim_rtcn_init_unit(&timer_unit[1], TPS_CLK, TMR_CLK); - sim_activate_after(&timer_unit[1], 1000000 / t); + t = sim_rtcn_init_unit(timer_clk_unit, TPS_CLK, TMR_CLK); + sim_activate_after(timer_clk_unit, 1000000 / t); } return SCPE_OK; @@ -475,9 +483,11 @@ t_stat timer1_svc(UNIT *uptr) } ticks = ctr->divider / TIMER_STP_US; - if (ticks == 0) { + + if (ticks < CLK_MIN_TICKS) { ticks = TPS_CLK; } + t = sim_rtcn_calb(ticks, TMR_CLK); sim_activate_after(uptr, (uint32) (1000000 / ticks)); @@ -517,10 +527,12 @@ uint32 timer_read(uint32 pa, size_t size) case TIMER_REG_DIVA: case TIMER_REG_DIVB: case TIMER_REG_DIVC: - if (ctr->enabled && ctr->gate) { - ctr_val = timer_current_val(ctr); - } else { - ctr_val = ctr->divider; + ctr_val = ctr->val; + + if (ctr_val != ctr->divider) { + sim_debug(READ_MSG, &timer_dev, + "[%08x] >>> ctr_val = %04x, ctr->divider = %04x\n", + R[NUM_PC], ctr_val, ctr->divider); } switch (ctr->mode & CLK_RW) { @@ -565,24 +577,39 @@ void handle_timer_write(uint8 ctrnum, uint32 val) case 0x10: ctr->divider &= 0xff00; ctr->divider |= val & 0xff; + ctr->val = ctr->divider; ctr->enabled = TRUE; ctr->stime = sim_gtime(); + sim_cancel(timer_clk_unit); + sim_activate_abs(timer_clk_unit, ctr->divider * TIMER_STP_US); break; case 0x20: ctr->divider &= 0x00ff; ctr->divider |= (val & 0xff) << 8; + ctr->val = ctr->divider; ctr->enabled = TRUE; ctr->stime = sim_gtime(); + /* Kick the timer to get the new divider value */ + sim_cancel(timer_clk_unit); + sim_activate_abs(timer_clk_unit, ctr->divider * TIMER_STP_US); break; case 0x30: if (ctr->lmb) { ctr->lmb = FALSE; ctr->divider = (uint16) ((ctr->divider & 0x00ff) | ((val & 0xff) << 8)); + ctr->val = ctr->divider; ctr->enabled = TRUE; ctr->stime = sim_gtime(); + sim_debug(READ_MSG, &timer_dev, + "[%08x] Write timer %d val LMB (MSB): %02x\n", + R[NUM_PC], ctrnum, val & 0xff); + /* Kick the timer to get the new divider value */ + sim_cancel(timer_clk_unit); + sim_activate_abs(timer_clk_unit, ctr->divider * TIMER_STP_US); } else { ctr->lmb = TRUE; ctr->divider = (ctr->divider & 0xff00) | (val & 0xff); + ctr->val = ctr->divider; } break; default: @@ -652,7 +679,7 @@ t_stat tod_reset(DEVICE *dptr) if (!sim_is_running) { t = sim_rtcn_init_unit(&tod_unit, TPS_TOD, TMR_TOD); - sim_activate_after(&tod_unit, 1000000 / TPS_TOD); + sim_activate_after(&tod_unit, 1000000 / t); } return SCPE_OK; diff --git a/3B2/3b2_sysdev.h b/3B2/3b2_sysdev.h index 10430554..078fdc08 100644 --- a/3B2/3b2_sysdev.h +++ b/3B2/3b2_sysdev.h @@ -43,6 +43,7 @@ extern DEBTAB sys_deb_tab[]; struct timer_ctr { uint16 divider; + uint16 val; uint8 mode; t_bool lmb; t_bool enabled;