TX-0: Make ^E work in readin mode.

sim_instr does not completely follow the outline in the SIMH v3
developer docs. It does not decrease sim_interval in readin mode.
Fixing this, I cleaned up some other things:

- Move the decrease of sim_interval to after the check for breakpoints,
  but before the check for ios. This ensures that sim_interval will
  decrease any time an instruction executes in normal mode, or readin
  mode executes, or ios is set and the CPU is waiting for ios to clear.
  (Except the CPU should be clearing ios itself, not waiting for ios to
  clear, but that fix requires a complete redesign of the I/O routines
  and belongs in another branch.)
- Correctly handle all four combinations of mod_tst and mod_rdin.
- When changing from readin mode to normal mode, if cpu_set_mode returns
  an error, stop with the same error. If cpu_set_mode returns SCPE_OK,
  either stop or continue execution, depending on the word read from tape.
- In petr_boot and in the readin mode code in sim_instr, if the
  PETR is not attached to a file, return SCPE_UNATT. Never try to read
  from an unattached unit; I believe this reads standard input and
  prevents ^E from working.

Overall control structure inside the while (reason == 0) loop:

- When stopping due to an error, break out of the while loop where
  possible.
- After handling "ios is set", continue, don't run readin/test/normal-
  mode code.
- After handling one readin operation, if the code didn't break out
  of the while loop, continue, don't run normal-mode code.
This commit is contained in:
Derek Peschel 2023-09-15 06:50:34 -07:00 committed by Paul Koning
parent 6474252ed4
commit cc97971dc9
2 changed files with 21 additions and 10 deletions

View file

@ -305,6 +305,8 @@ extern int32 drm (int32 inst, int32 dev, int32 dat);
extern int32 dpy (int32 ac); extern int32 dpy (int32 ac);
#endif #endif
extern UNIT petr_unit;
/* CPU data structures /* CPU data structures
cpu_dev CPU device descriptor cpu_dev CPU device descriptor
@ -471,14 +473,20 @@ t_stat sim_instr (void)
break; break;
} }
sim_interval = sim_interval - 1;
if (ios) { if (ios) {
TRACE_PRINT(ERROR_MSG, ("I/O Stop - Waiting...\n")); TRACE_PRINT(ERROR_MSG, ("I/O Stop - Waiting...\n"));
continue; continue; /* Don't execute test/readin/normal mode */
} }
/* Handle Instruction Execution in TEST and READIN modes */ /* Handle Instruction Execution in TEST and READIN modes */
if (mode_tst) { /* Test Mode / Readin mode */ if (mode_tst) { /* Test Mode / Readin mode */
if (mode_rdin) { /* Readin Mode */ if (mode_rdin) { /* Readin Mode */
if ((petr_unit.flags & UNIT_ATT) == 0)
return SCPE_UNATT;
reason = SCPE_OK; /* Default is to continue reading, and transfer control when done. */ reason = SCPE_OK; /* Default is to continue reading, and transfer control when done. */
AC = petr(3,0,0); /* Read three chars from tape into AC */ AC = petr(3,0,0); /* Read three chars from tape into AC */
MAR = AC & AMASK; /* Set memory address */ MAR = AC & AMASK; /* Set memory address */
@ -487,6 +495,7 @@ t_stat sim_instr (void)
if (!MEM_ADDR_OK(MAR)) { if (!MEM_ADDR_OK(MAR)) {
TRACE_PRINT(ERROR_MSG, ("READIN: Tape address out of range.\n")); TRACE_PRINT(ERROR_MSG, ("READIN: Tape address out of range.\n"));
reason = SCPE_FMT; reason = SCPE_FMT;
break;
} }
switch (IR) { switch (IR) {
@ -498,29 +507,29 @@ t_stat sim_instr (void)
break; break;
case 02: /* Transfer Control (trn x) Start Execution */ case 02: /* Transfer Control (trn x) Start Execution */
PC = MAR; PC = MAR;
reason = SCPE_OK; /* let SIMH start execution. */
TRACE_PRINT(READIN_MSG, ("READIN: trn %06o (Start Execution)\n", PC)); TRACE_PRINT(READIN_MSG, ("READIN: trn %06o (Start Execution)\n", PC));
reason = cpu_set_mode(&cpu_unit, 0, NULL, NULL); reason = cpu_set_mode(&cpu_unit, 0, NULL, NULL);
break; break;
case 01: /* Transfer (add x) - Halt */ case 01: /* Transfer (add x) - Halt */
PC = MAR; PC = MAR;
reason = SCPE_STOP; /* let SIMH halt. */
TRACE_PRINT(READIN_MSG, ("READIN: add %06o (Halt)\n", PC)); TRACE_PRINT(READIN_MSG, ("READIN: add %06o (Halt)\n", PC));
reason = cpu_set_mode(&cpu_unit, 0, NULL, NULL); reason = cpu_set_mode(&cpu_unit, 0, NULL, NULL);
if (reason == SCPE_OK) reason = SCPE_STOP; /* let SIMH halt. */
break; break;
default: default:
reason = SCPE_IERR; reason = SCPE_IERR;
break; break;
} }
} else if (mode_tst) { /* Test mode not implemented yet. */ continue; /* Don't fall into normal-mode processing. */
} else { /* Test mode not implemented yet. */
TRACE_PRINT(ERROR_MSG, ("TEST Mode not implemented.\n")); TRACE_PRINT(ERROR_MSG, ("TEST Mode not implemented.\n"));
reason = SCPE_STOP; reason = SCPE_STOP;
break;
} else {
TRACE_PRINT(ERROR_MSG, ("Invalid CPU mode.\n"));
reason = SCPE_IERR;
} }
continue; /* Proceed with next instruction */ } else if (mode_rdin) {
TRACE_PRINT(ERROR_MSG, ("Invalid CPU mode.\n"));
reason = SCPE_IERR;
break;
} }
/* Fetch, decode instruction in NORMAL mode */ /* Fetch, decode instruction in NORMAL mode */
@ -531,7 +540,6 @@ t_stat sim_instr (void)
inst_class = IR >> 3; inst_class = IR >> 3;
op = MBR & AMASK; op = MBR & AMASK;
y = MBR & YMASK; y = MBR & YMASK;
sim_interval = sim_interval - 1;
if ((cpu_unit.flags & UNIT_EXT_INST) == 0) { /* Original instruction set */ if ((cpu_unit.flags & UNIT_EXT_INST) == 0) { /* Original instruction set */
IR &= 030; IR &= 030;

View file

@ -414,6 +414,9 @@ t_stat petr_boot (int32 unitno, DEVICE *dptr)
int32 addr, tdata; int32 addr, tdata;
#endif /* SANITY_CHECK_TAPE */ #endif /* SANITY_CHECK_TAPE */
if ((petr_unit.flags & UNIT_ATT) == 0)
return SCPE_UNATT;
/* Switch to READIN mode. */ /* Switch to READIN mode. */
cpu_set_mode(&cpu_unit, UNIT_MODE_READIN, NULL, NULL); cpu_set_mode(&cpu_unit, UNIT_MODE_READIN, NULL, NULL);
#ifdef SANITY_CHECK_TAPE #ifdef SANITY_CHECK_TAPE