cpu/
control.rs

1//! Emulates the principal central components of the TX-2.
2//!
3//! # TX-2 Functionality implemented in this module
4//!
5//! The functionality of this module is conceptually similar to the
6//! CPU of a modern computer, although on the real TX-2 these
7//! functions were split across several identifiably separate units
8//! ("elements").
9//!
10//!
11//!
12//! ## Functions of the In/Out Element
13//!
14//!
15//! Other functions of the In/Out element are implemented in the [io]
16//! module.
17//!
18//! # Functions of the Exchange Element
19//!
20//! - Remember the setting of the TSP (Toggle Start Point) register
21//!
22use std::collections::{BTreeMap, HashSet};
23use std::fmt::Write;
24use std::ops::BitAnd;
25use std::time::Duration;
26
27use tracing::{Level, event, event_enabled, span};
28
29mod op_configuration;
30mod op_index;
31mod op_io;
32mod op_jump;
33mod op_loadstore;
34#[cfg(test)]
35mod tests;
36mod timing;
37mod trap;
38
39use base::instruction::{Inst, Instruction, Opcode, SymbolicInstruction};
40use base::prelude::*;
41use base::subword;
42
43use super::alarm::{Alarm, AlarmDetails, AlarmKind, Alarmer, BadMemOp};
44use super::alarmunit::AlarmUnit;
45use super::context::Context;
46use super::diagnostics::{CurrentInstructionDiagnostics, DiagnosticFetcher};
47use super::exchanger::{
48    SystemConfiguration, exchanged_value_for_load, exchanged_value_for_store,
49    standard_plugboard_f_memory_settings,
50};
51use super::io::DeviceManager;
52use super::memory::{self, ExtraBits, MemoryMapped, MemoryOpFailure, MemoryUnit, MetaBitChange};
53use super::*;
54
55use trap::TrapCircuit;
56
57#[derive(Debug, PartialEq, Eq, Clone, Copy)]
58pub enum RunMode {
59    Running,
60    InLimbo,
61}
62
63#[derive(Debug, Eq, PartialEq)]
64pub(crate) enum ProgramCounterChange {
65    /// Change of current sequence.
66    SequenceChange(Unsigned6Bit),
67
68    // A TSD instruction ends in dismiss-and-wait.  That is, the
69    // sequence is dismissed without its sequence number changing.
70    DismissAndWait(Address),
71
72    /// Immediate stop of execution, such as when an unmasked alarm is raised.
73    Stop(Address),
74
75    // Normal increment of the program counter.
76    CounterUpdate,
77
78    // Transfer control to another address (but without changing
79    // sequence).
80    Jump(Address),
81}
82
83/// Flags represent requests to run for instruction sequences (today
84/// one might describe these as threads).  Some sequences are special:
85///
86/// | Sequence Number | Description |
87/// | --------------- | ----------- |
88/// | 0   | Sequence which is run to start the computer (e.g. when "CODABO" or "START OVER" is pressed).                             |
89/// |41-75| hardware devices          |
90/// | 76  | Not for physical devices. |
91/// | 77  | Not for physical devices. |
92///
93/// The flag for sequences 76 and 77 may only be raised/lowered by
94/// program control.
95///
96/// The Lincoln Laboratory book "MIT Lincoln Laboratory: Technology in
97/// Support of National Security" states (on page 462) that The Xerox
98/// Alto also used sequences for I/O.  See also
99/// <https://en.wikipedia.org/wiki/Xerox_Alto#Architecture>
100#[derive(Debug)]
101struct SequenceFlags {
102    flag_values: u64,
103    flag_changes: u64,
104}
105
106fn ones_of_value_as_vec(mut bits: u64) -> Vec<SequenceNumber> {
107    let popcount_or_zero: usize = usize::try_from(bits.count_ones()).unwrap_or(0usize);
108    let mut result = Vec::with_capacity(popcount_or_zero);
109    while bits != 0 {
110        let pos = bits.trailing_zeros();
111        result.push(SequenceNumber::try_from(pos).expect("SequenceNumber::MAX should be > 32"));
112        bits &= !(1 << pos);
113    }
114    result
115}
116
117#[test]
118fn test_ones_of_value_as_vec() {
119    assert!(ones_of_value_as_vec(0).is_empty());
120    assert_eq!(ones_of_value_as_vec(0b1), vec![u6!(0)]);
121    assert_eq!(ones_of_value_as_vec(0b101), vec![u6!(0), u6!(2)]);
122}
123
124impl SequenceFlags {
125    fn new() -> SequenceFlags {
126        // New instances start with no flags raised (i.e. in "Limbo",
127        // STARTOVER not running).
128        SequenceFlags {
129            flag_values: 0,
130            flag_changes: 0,
131        }
132    }
133
134    fn lower_all(&mut self) {
135        self.flag_changes |= self.flag_values;
136        self.flag_values = 0;
137    }
138
139    fn flagbit(flag: &SequenceNumber) -> u64 {
140        1_u64 << u64::from(*flag)
141    }
142
143    fn lower(&mut self, flag: &SequenceNumber) {
144        // We create a u16 from *flag in order to perform the
145        // comparison.  Otherwise we get the compilation error
146        // "error[E0277]: can't compare `base::prelude::Unsigned6Bit`
147        // with `u16`".
148        #![allow(clippy::cmp_owned)]
149        assert!(u16::from(*flag) < 0o100_u16);
150        event!(Level::DEBUG, "Lowering flag {}", flag,);
151        let mask = SequenceFlags::flagbit(flag);
152        self.flag_values &= !mask;
153        self.flag_changes |= mask;
154    }
155
156    fn raise(&mut self, flag: &SequenceNumber) {
157        // We create a u16 from *flag in order to perform the
158        // comparison.  Otherwise we get the compilation error
159        // "error[E0277]: can't compare `base::prelude::Unsigned6Bit`
160        // with `u16`".
161        #![allow(clippy::cmp_owned)]
162        assert!(u16::from(*flag) < 0o100_u16);
163        let mask = SequenceFlags::flagbit(flag);
164        self.flag_values |= mask;
165        self.flag_changes |= mask;
166
167        if event_enabled!(Level::DEBUG) {
168            // Build the debug message which we are going to use; this
169            // is conditional only because it allocates memory and so
170            // is likely to be expensive.
171            let seqs: String = ones_of_value_as_vec(self.flag_values).into_iter().fold(
172                String::new(),
173                |mut acc, v| {
174                    write!(acc, "{:>02o} ", u64::from(v)).expect("write to string must succeed");
175                    acc
176                },
177            );
178            event!(
179                Level::DEBUG,
180                "Raised flag {flag:o}; runnable sequences now {seqs}"
181            );
182        }
183    }
184
185    fn current_flag_state(&self, flag: &SequenceNumber) -> bool {
186        // We create a u16 from *flag in order to perform the
187        // comparison.  Otherwise we get the compilation error
188        // "error[E0277]: can't compare `base::prelude::Unsigned6Bit`
189        // with `u16`".
190        #![allow(clippy::cmp_owned)]
191        assert!(u16::from(*flag) < 0o100_u16);
192        self.flag_values & SequenceFlags::flagbit(flag) != 0
193    }
194
195    /// Return the index of the highest-priority (lowest-numbered)
196    /// flag.  If no flag is raised (the machine is in "Limbo"),
197    /// return None.
198    fn highest_priority_raised_flag(&self) -> Option<SequenceNumber> {
199        let n = self.flag_values.trailing_zeros();
200        if n == 64 {
201            None
202        } else {
203            Some(n.try_into().unwrap())
204        }
205    }
206
207    fn drain_flag_changes(&mut self) -> Vec<SequenceNumber> {
208        let result = ones_of_value_as_vec(self.flag_changes);
209        self.flag_changes = 0;
210        result
211    }
212}
213
214#[test]
215fn test_sequence_flags_highest_priority_raised() {
216    let mut flags = SequenceFlags::new();
217    assert!(flags.drain_flag_changes().is_empty());
218
219    flags.lower_all();
220    assert_eq!(flags.highest_priority_raised_flag(), None);
221    // Lowering all flags produces no change, they were already down.
222    assert!(flags.drain_flag_changes().is_empty());
223
224    flags.raise(&Unsigned6Bit::ZERO);
225    assert_eq!(
226        flags.highest_priority_raised_flag().map(i8::from),
227        Some(0_i8)
228    );
229    assert_eq!(flags.drain_flag_changes(), vec![u6!(0)]);
230    flags.raise(&Unsigned6Bit::ONE);
231    // 0 is still raised, so it still has the highest priority.
232    assert_eq!(
233        flags.highest_priority_raised_flag(),
234        Some(Unsigned6Bit::ZERO)
235    );
236    assert_eq!(flags.drain_flag_changes(), vec![u6!(1)]);
237
238    flags.lower(&SequenceNumber::ZERO);
239    assert_eq!(
240        flags.highest_priority_raised_flag(),
241        Some(Unsigned6Bit::ONE)
242    );
243    flags.lower(&SequenceNumber::ONE);
244    assert_eq!(flags.drain_flag_changes(), vec![u6!(0), u6!(1)]);
245    assert_eq!(flags.highest_priority_raised_flag(), None);
246
247    let four = SequenceNumber::try_from(4_i8).expect("valid test data");
248    let six = SequenceNumber::try_from(6_i8).expect("valid test data");
249    flags.raise(&four);
250    flags.raise(&six);
251    assert_eq!(flags.highest_priority_raised_flag(), Some(four));
252    flags.lower(&four);
253    assert_eq!(flags.highest_priority_raised_flag(), Some(six));
254    assert_eq!(flags.drain_flag_changes(), vec![u6!(4), u6!(6)]);
255}
256
257#[test]
258fn test_sequence_flags_current_flag_state() {
259    let mut flags = SequenceFlags::new();
260    let s52: SequenceNumber = u6!(0o52);
261    flags.lower_all();
262    assert!(!flags.current_flag_state(&s52), "flag 52 should be lowered");
263    flags.raise(&s52);
264    assert!(flags.current_flag_state(&s52), "flag 52 should be raised");
265    assert_eq!(flags.drain_flag_changes(), vec![u6!(0o52)]);
266}
267
268/// Registers from various elements of the TX-2.
269///
270/// This includes both programmer-accessible registers (Index
271/// registers for example) and non-programmer accessible registers
272/// (such as the N register).
273#[derive(Debug)]
274pub struct ControlRegisters {
275    pub diagnostic_only: CurrentInstructionDiagnostics,
276
277    // Arithmetic Element registers (A-E) are actually in V-memory.
278    /// Contents of the simulated N register.
279    pub n: Instruction,
280    pub n_sym: Option<SymbolicInstruction>,
281
282    /// The P register is the program counter for the current sequence.
283    pub p: Address,
284
285    /// Contents of the simulaterd Q register.
286    pub q: Address,
287
288    /// The k register (User Guide section 4-3.1) holds the current
289    /// sequence number (User Guide section 5-24).  k is
290    /// `Option<SequenceNumber>` in order to allow the (emulated)
291    /// control unit to recognise a CODABO button as indicating a need
292    /// to change sequence from the control unit's initial state to
293    /// sequence 0.
294    ///
295    /// This likely doesn't reflect the actual operation of the TX-2
296    /// very well, and better understanding of the real operation of
297    /// the machine will likely change this.
298    ///
299    /// I think that perhaps section 12-2.6.2 of Volume 2 of the
300    /// technical manual may explain how the real TX-2 avoided this
301    /// problem, but I don't think I understand what that section says.
302    /// The text is:
303    ///
304    /// """12-2.6.2 XPS FLIP-FLOP LOGIC.  This flip-floop inhibits the
305    /// X Memory strobe pulse into X when the register selected has the
306    /// same address or the current program counter, is not register 0,
307    /// and this is the first reference to this register since the last
308    /// sequence change.  In this case all the cores of the register
309    /// are clearered and only "junk" (with a 50-50 chance of a bad
310    /// parity) would be strobed into X.  If XPS¹, then a clear pulse
311    /// is substituted for the strobe pulse.
312    ///
313    /// The flip-flop is set whenever a sequence change occurs, and is
314    /// cleared the first time thereafter that the program counter
315    /// register is referenced during a PK cycle (if ever).  See Fig
316    /// 12-8."""
317    pub k: Option<SequenceNumber>,
318
319    /// Start Point Register
320    spr: Address,
321
322    /// Index registers.
323    ///
324    /// Index register 0 is the Toggle Start point.
325    /// Index registers 40-77 are program counters for the sequences.
326    ///
327    /// The index registers form an 18-bit ring (as stated in the
328    /// description of the AUX instruction) and are described on page
329    /// 3-68 of the User Handbook (section 3-3.1) as being signed
330    /// integers.
331    pub index_regs: [Signed18Bit; 0o100], // AKA the X memory
332
333    /// the F memory
334    f_memory: [SystemConfiguration; 32],
335
336    /// The flags; these indicate which sequences are runnable.
337    flags: SequenceFlags,
338    current_sequence_is_runnable: bool,
339
340    /// `prev_hold` is set when the instruction we most previously
341    /// executed had the "hold" bit set.
342    prev_hold: bool,
343    // TODO: we may be able to eliminate prev_hold by moving the logic
344    // that's currently at the beginning of fetch_instruction() so
345    // that it occurs at the end of execute_instruction() instead.
346    // See the comment at the top of fetch_instruction().
347}
348
349impl ControlRegisters {
350    fn new(configuration_memory_config: ConfigurationMemorySetup) -> ControlRegisters {
351        let fmem = match configuration_memory_config {
352            ConfigurationMemorySetup::Uninitialised => {
353                let default_val = SystemConfiguration::from(0_u8);
354                [default_val; 32]
355            }
356            ConfigurationMemorySetup::StandardForTestingOnly => {
357                standard_plugboard_f_memory_settings()
358            }
359        };
360
361        let mut result = ControlRegisters {
362            diagnostic_only: CurrentInstructionDiagnostics {
363                current_instruction: Instruction::invalid(),
364                instruction_address: Address::from(u18!(0o777_777)),
365            },
366            n: Instruction::invalid(), // not a valid instruction
367            n_sym: None,
368            p: Address::default(),
369            q: Address::default(),
370            k: None, // not 0, so that we can recognise CODABO.
371            index_regs: [Signed18Bit::default(); 0o100],
372            f_memory: fmem,
373            flags: SequenceFlags::new(),
374            current_sequence_is_runnable: false,
375            prev_hold: false,
376            spr: Address::default(),
377        };
378        // Index register 0 always contains 0.  This should still be
379        // true if we modify the behaviour of Address::default(),
380        // which is why we override it here.
381        result.index_regs[0] = Signed18Bit::ZERO;
382        result
383    }
384
385    fn previous_instruction_hold(&self) -> bool {
386        // We cannot just check the N register for this, because when
387        // a TSD instruction ends in "dismiss and wait", the N
388        // register contains the (possibly held) TSD instruction, but
389        // it's the hold bit of the _previous_ instruction that
390        // matters.
391        self.prev_hold
392    }
393
394    fn set_spr(&mut self, addr: &Address) {
395        self.spr = *addr;
396    }
397
398    fn get_index_register(&self, n: Unsigned6Bit) -> Signed18Bit {
399        let n = usize::from(n);
400        assert_eq!(self.index_regs[0], 0);
401        assert!(n < 0o100);
402        self.index_regs[n]
403    }
404
405    fn get_index_register_as_address(&mut self, n: Unsigned6Bit) -> Address {
406        let value: Signed18Bit = self.get_index_register(n);
407        Address::from(value.reinterpret_as_unsigned())
408    }
409
410    fn set_index_register(&mut self, n: Unsigned6Bit, value: &Signed18Bit) {
411        let n = usize::from(n);
412        assert_eq!(self.index_regs[0], 0);
413        assert_ne!(n, 0, "Index register 0 should be fixed at 0");
414        assert!(n < 0o100);
415        self.index_regs[n] = *value;
416    }
417
418    fn set_index_register_from_address(&mut self, n: Unsigned6Bit, addr: &Address) {
419        let value: Unsigned18Bit = Unsigned18Bit::from(*addr);
420        self.set_index_register(n, &value.reinterpret_as_signed());
421    }
422
423    fn get_f_mem(&self, n: Unsigned5Bit) -> SystemConfiguration {
424        // Use u8::from in order to be able to compare an Unsigned5Bit.
425        #![allow(clippy::cmp_owned)]
426        assert!(u8::from(n) < 0o37_u8);
427        assert_eq!(self.f_memory[0], SystemConfiguration::zero());
428        let pos: usize = n.into();
429        self.f_memory[pos]
430    }
431
432    #[must_use]
433    pub fn current_flag_state(&self, seq: &Unsigned6Bit) -> bool {
434        self.flags.current_flag_state(seq)
435    }
436}
437
438impl DiagnosticFetcher for &ControlRegisters {
439    fn diagnostics(self) -> CurrentInstructionDiagnostics {
440        self.diagnostic_only.clone()
441    }
442}
443
444#[derive(Clone, Copy, Debug)]
445pub enum ResetMode {
446    ResetTSP = 0,
447    Reset0 = 0o0377710,
448    Reset1 = 0o0377711,
449    Reset2 = 0o0377712,
450    Reset3 = 0o0377713,
451    Reset4 = 0o0377714,
452    Reset5 = 0o0377715,
453    Reset6 = 0o0377716,
454    Reset7 = 0o0377717,
455}
456
457impl ResetMode {
458    fn address(&self, ctx: &Context, mem: &mut MemoryUnit) -> Option<Address> {
459        use ResetMode::*;
460        const PHYSICAL_ADDRESS_BITS: u32 = 0o377_777;
461        match self {
462            Reset0 | Reset1 | Reset2 | Reset3 | Reset4 | Reset5 | Reset6 | Reset7 => {
463                let loc: Address = Address::from(Unsigned18Bit::try_from(*self as u32).unwrap());
464                match mem.fetch(ctx, &loc, &MetaBitChange::None) {
465                    Ok((word, _)) => {
466                        // word is 36 bits wide but we only want the bottom 17 bits.
467                        let (left, right) = subword::split_halves(word);
468                        if left != 0 {
469                            // issue warning but otherwise ignore
470                            event!(
471                                Level::WARN,
472                                "Ignoring non-zero left subword of reset register {:o}, containing {:o} (left side is {:o})",
473                                loc,
474                                word,
475                                left
476                            );
477                        }
478                        // We assume that reset operations don't implement deferred addressing.
479                        let defer_bit = Unsigned18Bit::try_from(0o400_000).unwrap();
480                        if right & defer_bit != 0 {
481                            // issue warning but otherwise ignore
482                            event!(
483                                Level::WARN,
484                                "Ignoring non-zero defer bit of reset register {:o}, containing {:o}",
485                                loc,
486                                word
487                            );
488                        }
489
490                        let physical_address = Address::from(right & PHYSICAL_ADDRESS_BITS);
491                        Some(physical_address)
492                    }
493                    Err(e) => {
494                        panic!("failed to fetch reset {self:?}: {e}");
495                    }
496                }
497            }
498            ResetTSP => None, // need to read the TSP toggle switch.
499        }
500    }
501}
502
503/// `ControlUnit` simulates the operation of the Control Element of the TX-2 computer.
504///
505#[derive(Debug)]
506pub struct ControlUnit {
507    regs: ControlRegisters,
508    trap: TrapCircuit,
509    alarm_unit: AlarmUnit,
510}
511
512fn sign_extend_index_value(index_val: &Signed18Bit) -> Unsigned36Bit {
513    let left = if index_val.is_negative() {
514        Unsigned18Bit::MAX
515    } else {
516        Unsigned18Bit::ZERO
517    };
518    subword::join_halves(left, index_val.reinterpret_as_unsigned())
519}
520
521#[derive(Debug, PartialEq, Eq, Default)]
522pub(crate) struct OpcodeResult {
523    program_counter_change: Option<ProgramCounterChange>,
524    poll_order_change: Option<SequenceNumber>,
525    output: Option<OutputEvent>,
526}
527
528#[test]
529fn test_opcode_result() {
530    let r = OpcodeResult::default();
531    assert!(r.program_counter_change.is_none());
532    assert!(r.poll_order_change.is_none());
533}
534
535#[derive(Debug, Clone, PartialEq, Eq)]
536pub enum PanicOnUnmaskedAlarm {
537    No,
538    Yes,
539}
540
541#[derive(Debug, Clone, PartialEq, Eq)]
542pub enum ConfigurationMemorySetup {
543    Uninitialised,
544    StandardForTestingOnly,
545}
546
547fn please_poll_soon(ctx: &Context, devices: &mut DeviceManager, seq: SequenceNumber) {
548    event!(
549        Level::TRACE,
550        "please_poll_soon: seq={:?}, requesting poll at {:?}",
551        seq,
552        &ctx.simulated_time
553    );
554    devices.update_poll_time(ctx, seq);
555}
556
557impl ControlUnit {
558    #[must_use]
559    pub fn new(
560        panic_on_unmasked_alarm: PanicOnUnmaskedAlarm,
561        configuration_memory_config: ConfigurationMemorySetup,
562    ) -> ControlUnit {
563        ControlUnit {
564            regs: ControlRegisters::new(configuration_memory_config),
565            trap: TrapCircuit::new(),
566            alarm_unit: AlarmUnit::new_with_panic(match panic_on_unmasked_alarm {
567                PanicOnUnmaskedAlarm::No => false,
568                PanicOnUnmaskedAlarm::Yes => true,
569            }),
570        }
571    }
572
573    #[must_use]
574    pub fn diagnostics(&self) -> &CurrentInstructionDiagnostics {
575        &self.regs.diagnostic_only
576    }
577
578    fn make_alarm(&self, details: AlarmDetails) -> Alarm {
579        Alarm {
580            sequence: self.regs.k,
581            details,
582        }
583    }
584
585    fn fire_details_if_not_masked(&mut self, alarm_details: AlarmDetails) -> Result<(), Alarm> {
586        let diagnostics: CurrentInstructionDiagnostics = self.diagnostics().clone();
587        self.alarm_unit
588            .fire_if_not_masked(self.make_alarm(alarm_details), diagnostics)
589    }
590
591    pub fn set_alarm_masked(&mut self, kind: AlarmKind, masked: bool) -> Result<(), Alarm> {
592        if masked {
593            self.alarm_unit.mask(kind, &self.regs.diagnostic_only)
594        } else {
595            self.alarm_unit.unmask(kind);
596            Ok(())
597        }
598    }
599
600    #[must_use]
601    pub fn unmasked_alarm_active(&self) -> bool {
602        self.alarm_unit.unmasked_alarm_active()
603    }
604
605    #[must_use]
606    pub fn get_status_of_alarm(&self, name: &str) -> Option<AlarmStatus> {
607        self.alarm_unit.get_status_of_alarm(name)
608    }
609
610    #[must_use]
611    pub fn get_alarm_statuses(&self) -> Vec<AlarmStatus> {
612        self.alarm_unit.get_alarm_statuses()
613    }
614
615    pub fn set_metabits_disabled(&mut self, disable: bool) {
616        self.trap.set_metabits_disabled(disable);
617    }
618
619    /// There are actually 9 different CODABO buttons (see page 5-18
620    /// of the User Guide).  There are also 9 corresponding RESET
621    /// buttons.  Each RESET button has a corresponding CODABO button.
622    /// See the `reset` method for address assignments.
623    ///
624    /// The CODABO operation leaves the Start Point Register set to
625    /// the selected start point.  There are also 9 reset buttons
626    /// which perform a similar task.
627    ///
628    /// Pressing the main CODABO button (the one which uses the Toggle
629    /// Start Point register) will result in memory being cleared,
630    /// F-memory being set up in a standard way, and then a program
631    /// being read from the paper tape reader using the standard
632    /// readin program set up on the plugboard.
633    ///
634    /// The standard readin program executes the program it read in
635    /// from the address specified by the program.  The program
636    /// executes as sequence 52 (PETR) with the PETR unit initially
637    /// turned off.
638    ///
639    /// The Users Handbook (page 5-18) states that flags are cleared
640    /// but it doesn't state anywhere that any registers are reset.
641    /// So we don't do that.  But there's no unit test for that, since
642    /// I haven't found (or cannot recall) a piece of documentation
643    /// which states that this is so.
644    pub fn codabo(
645        &mut self,
646        ctx: &Context,
647        reset_mode: &ResetMode,
648        devices: &mut DeviceManager,
649        mem: &mut MemoryUnit,
650    ) -> Result<(), Alarm> {
651        // We probably don't need an equivalent of resetting the
652        // control flip-flops in an emulator.  But if we did, that
653        // would happen here.
654        //
655        // On the other hand, the P register is described as an
656        // "18-bit flip-flop" in section 4-2.2 of the User Handbook,
657        // so perhaps all the registers in V memory are cleared by
658        // CODABO.
659        //
660        let span = span!(Level::ERROR,
661                         "codabo",
662                         reset_mode=?reset_mode);
663        let _enter = span.enter();
664        event!(Level::INFO, "Starting CODABO {:?}", &reset_mode);
665        // CODABO's first action is supposed to be "STOP" but the
666        // simulator has no analogue for "STOP".  One reason we need
667        // to perform STOP is that PRESET has no effect unless the
668        // computer is stopped.
669        self.clear_alarms();
670        self.preset(ctx, devices)?;
671        self.startover(ctx, reset_mode, mem);
672        self.calaco();
673        event!(
674            Level::DEBUG,
675            "After CODABO, control unit contains {:#?}",
676            &self
677        );
678        Ok(())
679    }
680
681    /// Simulate the effect of the PRESET button.  This is described
682    /// on page 5-19 of the Users Handbook. It:
683    /// 1. clears all flags
684    /// 2. Clears all "Connect" flip-flops
685    /// 3. Set all interlocks and indicators to their proper "PRESET" value.
686    ///
687    /// PRESET is supposedly interlocked so that it is ineffective
688    /// unless the machine is in the STOP state.  But our simulation,
689    /// right now, has no representation for the STOP state.
690    fn preset(&mut self, ctx: &Context, devices: &mut DeviceManager) -> Result<(), Alarm> {
691        // 1. Clear all flags.
692        self.regs.flags.lower_all();
693        // 2. Clear all "Connect" flip-flops
694        self.disconnect_all_devices(ctx, devices)
695        // 3. Set all interlocks and indicators to their proper "PRESET" value.
696        // (interlocks are not simulated)
697    }
698
699    /// Simulate the effect of the CALACO button.  This is described
700    /// on page 5-19 of the Users Handbook.
701    fn calaco(&mut self) {
702        self.clear_alarms();
703        // TODO: there is currently no simulator representation for
704        // STOP/START, but CALACO is supposed to perform START.  This
705        // might be relevant because PRESET is supposet to have no
706        // effect unless the computer is in the stopped state.
707    }
708
709    fn clear_alarms(&mut self) {
710        self.alarm_unit.clear_all_alarms();
711    }
712
713    pub fn disconnect_all_devices(
714        &mut self,
715        ctx: &Context,
716        devices: &mut DeviceManager,
717    ) -> Result<(), Alarm> {
718        devices.disconnect_all(ctx, &mut self.alarm_unit)
719    }
720
721    /// There are 9 separate RESET buttons, for 8 fixed addresses and
722    /// another which uses the Toggle Start Point register.  There
723    /// appear to be two Toggle Start Point switches, one on the front
724    /// panel and a second on a remote control unit.  The
725    /// fixed-address RESET buttons correspond to the fixed
726    /// addresses 3777710 through 3777717, inclusive.
727    ///
728    /// RESET *only* loads the Start Point Register, nothing else.
729    pub fn reset(&mut self, ctx: &Context, reset_mode: &ResetMode, mem: &mut MemoryUnit) {
730        self.regs.set_spr(&match reset_mode.address(ctx, mem) {
731            Some(address) => address,
732            None => self.tsp(),
733        });
734    }
735
736    /// Handle press of STARTOVER (or part of the operation of
737    /// CODABO).  STARTOVER does RESET and then raises flag zero.
738    pub fn startover(&mut self, ctx: &Context, reset_mode: &ResetMode, mem: &mut MemoryUnit) {
739        self.reset(ctx, reset_mode, mem);
740        self.regs.current_sequence_is_runnable = false;
741        self.regs.flags.raise(&SequenceNumber::ZERO);
742        self.change_sequence(mem, None, SequenceNumber::ZERO);
743    }
744
745    /// Return the value in the Toggle Start Register (TSP).
746    ///
747    /// The TSP is a set of toggle switches on the TX-2's console (see
748    /// the TX-2 Users Handbook section 4-2.2).
749    ///
750    /// For now, we haven't made it configurable (i.e. have not
751    /// emulated the hardware) yet. We just hard-code it to point at
752    /// the F-memory configuration routine (which does its job and
753    /// then invokes the standard tape reader).
754    ///
755    /// # Caveat
756    ///
757    /// We used to set this to point at the "Memory Clear / Memory
758    /// Smear" program in the plugboard (see
759    /// [`memory::get_standard_plugboard()`]), but that accesses
760    /// addresses which are not mapped (e.g. the gap between U-memory
761    /// and V-memory) and so should only be run qith QSAL disabled,
762    /// which is not our default config.
763    ///
764    /// We should double-check how the TX-2's TSP was normally set and
765    /// how the TX-2 behaved around this.
766    fn tsp(&self) -> Address {
767        // The operation of RESET (or CODABO) will copy this value
768        // into the zeroth index register (which the program counter
769        // placeholder for sequence 0).
770        memory::STANDARD_PROGRAM_INIT_CONFIG
771    }
772
773    fn trap_seq() -> Unsigned6Bit {
774        Unsigned6Bit::try_from(0o42).unwrap()
775    }
776
777    fn raise_trap(&mut self) {
778        self.regs.flags.raise(&Self::trap_seq());
779    }
780
781    fn change_sequence(
782        &mut self,
783        mem: &mut MemoryUnit,
784        prev_seq: Option<SequenceNumber>,
785        mut next_seq: SequenceNumber,
786    ) {
787        fn is_marked_placeholder(index_val: &Signed18Bit) -> bool {
788            index_val < &0
789        }
790
791        // If the "Trap on Change Sequence" is enabled and the new
792        // sequence is marked (bit 2.9 of its index register is set).
793        // Activate unit 0o42, unless that's the unit which is giving
794        // up control.
795        //
796        // I'm not sure what should happen for the alternative case,
797        // where a unit of higher priority than 0o42 is marked for
798        // trap-on-sequence-change.
799        if prev_seq == Some(next_seq) {
800            event!(
801                Level::WARN,
802                "change_sequence: old and new sequences are the same: {:>02o}",
803                u8::from(next_seq),
804            );
805            return;
806        }
807
808        event!(
809            Level::DEBUG,
810            "Changing sequence to {:>02o}",
811            u8::from(next_seq),
812        );
813
814        let trap_seq = Self::trap_seq();
815        let sequence_change_trap = self.trap.trap_on_changed_sequence()
816            && is_marked_placeholder(&self.regs.get_index_register(next_seq))
817            && self.regs.k != Some(trap_seq)
818            && next_seq > trap_seq;
819
820        let previous_sequence: Unsigned6Bit = match prev_seq {
821            None => Unsigned6Bit::ZERO,
822            Some(n) => n,
823        };
824        // Update the E register as specified in section 4-3.1 of the
825        // Users Handbook.
826        mem.set_e_register(join_halves(
827            join_quarters(
828                Unsigned9Bit::from(previous_sequence),
829                Unsigned9Bit::from(next_seq),
830            ),
831            Unsigned18Bit::from(self.regs.p),
832        ));
833
834        if sequence_change_trap {
835            self.regs.flags.raise(&trap_seq);
836            next_seq = trap_seq;
837        }
838        self.regs.k = Some(next_seq);
839        if let Some(prev) = prev_seq {
840            // Index register 0 never changes, it's always 0.
841            if prev_seq != Some(Unsigned6Bit::ZERO) {
842                let p = self.regs.p;
843                self.regs.set_index_register_from_address(prev, &p);
844            }
845        }
846        self.set_program_counter(ProgramCounterChange::SequenceChange(next_seq));
847    }
848
849    fn set_program_counter(&mut self, change: ProgramCounterChange) {
850        match change {
851            ProgramCounterChange::Stop(p) => {
852                let old_mark = self.regs.p.split().1;
853                let new_mark: bool = p.split().1;
854                assert_eq!(old_mark, new_mark);
855                self.regs.p = p;
856            }
857            ProgramCounterChange::SequenceChange(next_seq) => {
858                // According to the Technical Manual, page 12-6,
859                // change of seqeuence is the only time in which P₂.₉
860                // is altered.
861                //
862                // However, see also the arm for the
863                // [`ProgramCounterChange::CounterUpdate`] case
864                // below.
865                if next_seq != 0 {
866                    self.regs.p = self.regs.get_index_register_as_address(next_seq);
867                    event!(
868                        Level::INFO,
869                        "Changed sequence to {:>02o} with P={:>06o}",
870                        u8::from(next_seq),
871                        self.regs.p
872                    );
873                } else {
874                    // Index register 0 is always 0, but by setting
875                    // the Toggle Status Register, the user can run
876                    // sequence 0 from an arbitrary address. That
877                    // address can't be stored in index register 0
878                    // since that's always 0, so we use an internal
879                    // "spr" register which is updated by the
880                    // RESET/CODABO buttons.  Here, we copy that saved
881                    // value into P.
882                    self.regs.p = self.regs.spr;
883                    event!(
884                        Level::INFO,
885                        "Starting sequence 0 with P={:>06o}",
886                        self.regs.p
887                    );
888                }
889            }
890            ProgramCounterChange::CounterUpdate => {
891                // Discussion: does this change the top bit (2.9)?
892                //
893                // Reasons for the answer "no"
894                // --------------------------
895                // Volume 2 of the Technical Manual (section 12-2.3 "P
896                // REGISTER DRIVER LOGIC") states, """Information can
897                // be transferred into the P register only from the X
898                // Adder.  In addition to this single transfer path,
899                // ther P register has a counter which can index the
900                // contents of the P register by one.  Note that count
901                // circuit does not alter the contents of P₂.₉"""
902                //
903                // Since P₂.₉ is the sign bit, this means that the P
904                // register wraps rather than overflows.
905                //
906                // As a practical matter, this wrap-around case means
907                // that self.regs.p previously contained 377,777.
908                // That is the last instruction in V Memory.  This is
909                // normally an unconditional JMP.  So in the standard
910                // plugboard configuration, we're going to take the
911                // jmp, meaning that we're never going to fetch an
912                // instruction from the address we just computed.
913                // But, this case may be needed to cover non-standard
914                // plugboard configurations.  According to the
915                // Technical Manual, page 12-6, change of seqeuence is
916                // the only time in which P₂.₉ is altered.
917                //
918                //
919                // Reasons for the answer "yes"
920                // ---------------------------
921                //
922                // The Instruction Execution chart on page 3-71 of the
923                // Users Handbook shows that the P register is updated
924                // to P+1 (see top row of table) and there is a
925                // reference to note 1.  This note is on page 3073
926                // (section 3-3.3) and it says:
927                //
928                // In all expressions P + 1, P + 2, sums are reducible 2¹⁸.
929                // (777777 + 1) mod 2¹⁸ = 0.
930                //
931                // This seems to directly contradict section 12-2.3 of
932                // the Technical Manual (which we referenced in the
933                // "no" section above).
934                //
935                // This seems a clear statement that bit 2.9 is used
936                // as the most significant bit.  It also seems to
937                // imply that if P=377777, P+1 will increment it to
938                // 400000.
939                let (_old_physical, old_mark) = self.regs.p.split();
940                let new_p = self.regs.p.successor(); // p now points at the next instruction.
941                let (_new_physical, new_mark) = new_p.split();
942                assert_eq!(old_mark, new_mark);
943                self.regs.p = new_p;
944            }
945            ProgramCounterChange::DismissAndWait(new_p) | ProgramCounterChange::Jump(new_p) => {
946                // Copy the value of P₂.₉ into `old_mark`.
947                let (_old_physical, old_mark) = self.regs.p.split();
948                // Update P, keeping the old value of P₂.₉.
949                self.regs.p = Address::join(new_p.into(), old_mark);
950            }
951        }
952    }
953
954    /// Consider whether a change of sequence is needed.  If yes,
955    /// perform the change.
956    fn select_sequence(&mut self, mem: &mut MemoryUnit) -> RunMode {
957        if self.regs.previous_instruction_hold() {
958            event!(
959                Level::DEBUG,
960                concat!(
961                    "Hold bit of previous instruction was set, ",
962                    "so we will not consider a sequence change"
963                )
964            );
965            RunMode::Running
966        } else {
967            // Handle any possible change of sequence.
968            match self.regs.flags.highest_priority_raised_flag() {
969                None => {
970                    // The current sequence's flag is no longer raised.
971                    //
972                    // This happens either because the sequence was
973                    // dismissed (permanent or temporary drop-out) or IOSj
974                    // 40000 ("LOWER FLAG J") had been issued.  In the
975                    // latter case, the current sequence should continue
976                    // to run until another sequence's flag is raised.
977                    if self.regs.current_sequence_is_runnable {
978                        event!(
979                            Level::DEBUG,
980                            "No flag is raised, but the current sequence is still runnable"
981                        );
982                        RunMode::Running
983                    } else {
984                        event!(
985                            Level::DEBUG,
986                            "No flags raised and current sequence is not runnable: in LIMBO"
987                        );
988                        RunMode::InLimbo
989                    }
990                }
991                Some(seq) => {
992                    event!(Level::TRACE, "Highest-priority sequence is {}", seq);
993                    if Some(seq) > self.regs.k
994                        || (!self.regs.current_sequence_is_runnable && Some(seq) < self.regs.k)
995                    {
996                        self.change_sequence(mem, self.regs.k, seq);
997                        RunMode::Running
998                    } else {
999                        // No sequence change, just carry on.
1000                        RunMode::Running
1001                    }
1002                }
1003            }
1004        }
1005    }
1006
1007    fn fetch_instruction(&mut self, ctx: &Context, mem: &mut MemoryUnit) -> Result<(), Alarm> {
1008        // TODO: This implementation begins the instruction fetch
1009        // operation by considering a possible change of sequence.
1010        // The TX-2 itself considers a sequence change as the PK cycle
1011        // is completed, in the resting state PK⁰⁰.  So it might make
1012        // more sense to move the sequence-change logic to the end of
1013        // the instructino-execution implementation. That will likely
1014        // make it simpler to implement the "hold" bit and
1015        // dismiss-and-wait (i.e. cases where we don't increment the
1016        // sequence's program counter).  When considering this option,
1017        // it's a good idea to re-read section 9-4 of Volume 2 of the
1018        // Technical Manual.
1019
1020        // If the previous instruction was held, we don't even scan
1021        // the flags.  This follows the description of how control
1022        // handles flags in section 4-3.5 of the User Handbook (page
1023        // 4-8).
1024        // Calculate the address from which we will fetch the
1025        // instruction, and the increment the program counter.
1026        let p_physical_address = Address::from(self.regs.p.split().0);
1027        self.regs.diagnostic_only.instruction_address = p_physical_address;
1028        event!(
1029            Level::TRACE,
1030            "Fetching instruction from physical address {p_physical_address:>012o}"
1031        );
1032        // Actually fetch the instruction.
1033        let meta_op = if self.trap.set_metabits_of_instructions() {
1034            MetaBitChange::Set
1035        } else {
1036            MetaBitChange::None
1037        };
1038        let instruction_word: Unsigned36Bit = match mem.fetch(ctx, &p_physical_address, &meta_op) {
1039            Ok((inst, extra_bits)) => {
1040                if extra_bits.meta && self.trap.trap_on_marked_instruction() {
1041                    self.raise_trap();
1042                }
1043                inst
1044            }
1045            Err(e) => match e {
1046                MemoryOpFailure::NotMapped(addr) => {
1047                    self.alarm_unit.fire_if_not_masked(
1048                        Alarm {
1049                            sequence: self.regs.k,
1050                            details: AlarmDetails::PSAL(
1051                                u32::from(addr),
1052                                "memory unit indicated physical address is not mapped".to_string(),
1053                            ),
1054                        },
1055                        &self.regs.diagnostic_only,
1056                    )?;
1057                    // PSAL is masked, but we don't know what
1058                    // instruction to execute, since we couldn't fetch
1059                    // one.  The program counter will not be updated
1060                    // until we call execute_instruction(), so we
1061                    // shouldn't increment it here.  So we just return
1062                    // a held instruction which is not otherwise
1063                    // valid.
1064                    Unsigned36Bit::from(Instruction::invalid())
1065                }
1066                MemoryOpFailure::ReadOnly(_, _) => unreachable!(),
1067            },
1068        };
1069        if let Some(k) = self.regs.k {
1070            event!(
1071                Level::TRACE,
1072                "Seq {:o} fetched instruction {:>012o} from physical address {:>012o}",
1073                k,
1074                instruction_word,
1075                p_physical_address
1076            );
1077        } else {
1078            event!(
1079                Level::ERROR,
1080                "Unspecified sequence fetched instruction {:>012o} from physical address {:>012o}",
1081                instruction_word,
1082                p_physical_address
1083            );
1084        }
1085        // Several things update the N register, so we update
1086        // `current_instruction` directly here instead of inside
1087        // update_n_register().
1088        self.regs.diagnostic_only.current_instruction = Instruction::from(instruction_word);
1089        self.update_n_register(instruction_word)?;
1090        Ok(())
1091    }
1092
1093    pub fn poll_hardware(
1094        &mut self,
1095        ctx: &Context,
1096        devices: &mut DeviceManager,
1097        mut run_mode: RunMode,
1098    ) -> Result<(RunMode, Option<Duration>), Alarm> {
1099        let (mut raised_flags, alarm, next_poll) = devices.poll(ctx, &mut self.alarm_unit)?;
1100        // If there are no hardware flags being raised, we may still
1101        // not be in limbo if there were already runnable sequences.
1102        // That is, if some sequence's flag was raised.  The hardware
1103        // devices can raise flags but not lower them.  Therefore if
1104        // run_mode was RunMode::Running on entry to this function, we
1105        // must return RunMode::Running.
1106        if raised_flags != 0 {
1107            run_mode = RunMode::Running;
1108        }
1109
1110        // For each newly-raised flag, raise the flag in self.flags.
1111        let raise_count = raised_flags.count_ones();
1112        if raise_count > 0 {
1113            event!(
1114                Level::DEBUG,
1115                "poll_hardware: {raise_count:2} new flag raises: {raised_flags:#o}"
1116            );
1117        } else {
1118            event!(Level::TRACE, "poll_hardware: no new flag raises");
1119        }
1120        for bitpos in 0.. {
1121            if raised_flags == 0 {
1122                break;
1123            }
1124            let mask = 1_u64 << bitpos;
1125            if raised_flags & mask != 0 {
1126                match SequenceNumber::try_from(bitpos) {
1127                    Ok(unit) => {
1128                        self.regs.flags.raise(&unit);
1129                    }
1130                    Err(_) => {
1131                        break;
1132                    }
1133                }
1134            }
1135            raised_flags &= !mask;
1136        }
1137
1138        // If a device raised an alarm, generate that alarm now.  This
1139        // alarm was not an error return from the poll() method,
1140        // because we needed to ensure that all flag raised were
1141        // processed.
1142        if let Some(active) = alarm {
1143            event!(
1144                Level::INFO,
1145                "poll_hardware: an alarm is active: {:?}",
1146                active
1147            );
1148            Err(active)
1149        } else {
1150            Ok((run_mode, next_poll))
1151        }
1152    }
1153
1154    fn update_n_register(&mut self, instruction_word: Unsigned36Bit) -> Result<(), Alarm> {
1155        self.regs.n = Instruction::from(instruction_word);
1156        if let Ok(symbolic) = SymbolicInstruction::try_from(&self.regs.n) {
1157            self.regs.n_sym = Some(symbolic);
1158            Ok(()) // valid instruction
1159        } else {
1160            self.alarm_unit
1161                .fire_if_not_masked(self.invalid_opcode_alarm(), &self.regs.diagnostic_only)?;
1162            self.regs.n_sym = None;
1163            Ok(()) // invalid instruction, but OCSAL is masked.
1164        }
1165    }
1166
1167    fn invalid_opcode_alarm(&self) -> Alarm {
1168        Alarm {
1169            sequence: self.regs.k,
1170            details: AlarmDetails::OCSAL(
1171                self.regs.n,
1172                format!("invalid opcode {:#o}", self.regs.n.opcode_number()),
1173            ),
1174        }
1175    }
1176
1177    fn invalid_opr_subcode(&self, bit2dot7: bool) -> Alarm {
1178        let opcode = self.regs.n.opcode_number();
1179        let ch: char = if bit2dot7 { '1' } else { '0' };
1180        Alarm {
1181            sequence: self.regs.k,
1182            details: AlarmDetails::OCSAL(
1183                self.regs.n,
1184                format!(
1185                    "Opcode OPR/IOS/AOP used with opcode {opcode:#o} and invalid subcode 1{ch}"
1186                ),
1187            ),
1188        }
1189    }
1190
1191    fn estimate_execute_time_ns(&self, orig_inst: &Instruction) -> u64 {
1192        let inst_from: Address = self.regs.p; // this is now P+1 but likely in the same memory type.
1193        let defer_from = match orig_inst.operand_address().split() {
1194            (true, physical) => Some(physical),
1195            (false, _) => None,
1196        };
1197
1198        // TODO: handle chains of deferred loads
1199        let operand_from: Option<Address> = match self.regs.n.operand_address().split() {
1200            (true, physical) => Some(physical),
1201            (false, _) => None,
1202        };
1203
1204        timing::estimate_instruction_ns(
1205            inst_from,
1206            orig_inst.opcode_number(),
1207            defer_from,
1208            operand_from,
1209        )
1210    }
1211
1212    /// Fetch and execute the next instruction pointed to by the P
1213    /// register.  Returns the estimated number of nanoseconds needed
1214    /// to execute the instruction.
1215    pub fn execute_instruction(
1216        &mut self,
1217        ctx: &Context,
1218        devices: &mut DeviceManager,
1219        mem: &mut MemoryUnit,
1220        poll_order_change: &mut Option<SequenceNumber>,
1221    ) -> Result<(u64, RunMode, Option<OutputEvent>), (Alarm, Address)> {
1222        fn execute(
1223            ctx: &Context,
1224            prev_program_counter: Address,
1225            opcode: &Opcode,
1226            control: &mut ControlUnit,
1227            devices: &mut DeviceManager,
1228            mem: &mut MemoryUnit,
1229        ) -> Result<OpcodeResult, Alarm> {
1230            match opcode {
1231                Opcode::Aux => control.op_aux(ctx, mem),
1232                Opcode::Lda => control.op_lda(ctx, mem),
1233                Opcode::Ldb => control.op_ldb(ctx, mem),
1234                Opcode::Ldc => control.op_ldc(ctx, mem),
1235                Opcode::Ldd => control.op_ldd(ctx, mem),
1236                Opcode::Lde => control.op_lde(ctx, mem),
1237                Opcode::Sta => control.op_sta(ctx, mem),
1238                Opcode::Stb => control.op_stb(ctx, mem),
1239                Opcode::Stc => control.op_stc(ctx, mem),
1240                Opcode::Std => control.op_std(ctx, mem),
1241                Opcode::Ste => control.op_ste(ctx, mem),
1242                Opcode::Rsx => control.op_rsx(ctx, mem),
1243                Opcode::Skx => control.op_skx(ctx),
1244                Opcode::Dpx => control.op_dpx(ctx, mem),
1245                Opcode::Jmp => control.op_jmp(ctx, mem),
1246                Opcode::Jpx => control.op_jpx(ctx, mem),
1247                Opcode::Jnx => control.op_jnx(ctx, mem),
1248                Opcode::Skm => control.op_skm(ctx, mem),
1249                Opcode::Spg => control.op_spg(ctx, mem),
1250                Opcode::Opr => control.op_opr(ctx, mem, devices), // Usually IOS.
1251                Opcode::Tsd => control.op_tsd(ctx, devices, prev_program_counter, mem),
1252                Opcode::Sed => control.op_sed(ctx, mem),
1253                Opcode::Exx => Err(Alarm {
1254                    sequence: control.regs.k,
1255                    details: AlarmDetails::ROUNDTUITAL {
1256                        explanation: "The emulator does not yet implement opcode EXX".to_string(),
1257                        bug_report_url: "https://github.com/TX-2/TX-2-simulator/issues/16",
1258                    },
1259                }),
1260                Opcode::Adx => Err(Alarm {
1261                    sequence: control.regs.k,
1262                    details: AlarmDetails::ROUNDTUITAL {
1263                        explanation: "The emulator does not yet implement opcode ADX".to_string(),
1264                        bug_report_url: "https://github.com/TX-2/TX-2-simulator/issues/18",
1265                    },
1266                }),
1267                Opcode::Spf => Err(Alarm {
1268                    sequence: control.regs.k,
1269                    details: AlarmDetails::ROUNDTUITAL {
1270                        explanation: "The emulator does not yet implement opcode SPF".to_string(),
1271                        bug_report_url: "https://github.com/TX-2/TX-2-simulator/issues/13",
1272                    },
1273                }),
1274                Opcode::Flf | Opcode::Flg => Err(Alarm {
1275                    sequence: control.regs.k,
1276                    details: AlarmDetails::ROUNDTUITAL {
1277                        explanation: "The emulator does not yet implement opcode {opcode}"
1278                            .to_string(),
1279                        // Note: that bug report covers two opcodes.
1280                        bug_report_url: "https://github.com/TX-2/TX-2-simulator/issues/14",
1281                    },
1282                }),
1283                Opcode::Ite | Opcode::Ita | Opcode::Una | Opcode::Dsa => Err(Alarm {
1284                    sequence: control.regs.k,
1285                    details: AlarmDetails::ROUNDTUITAL {
1286                        explanation: "The emulator does not yet implement opcode {opcode}"
1287                            .to_string(),
1288                        // Note: this bug report covers several opcodes.
1289                        bug_report_url: "https://github.com/TX-2/TX-2-simulator/issues/25",
1290                    },
1291                }),
1292                Opcode::Jov => Err(Alarm {
1293                    sequence: control.regs.k,
1294                    details: AlarmDetails::ROUNDTUITAL {
1295                        explanation: "The emulator does not yet implement opcode JOV".to_string(),
1296                        bug_report_url: "https://github.com/TX-2/TX-2-simulator/issues/11",
1297                    },
1298                }),
1299                Opcode::Jpa => Err(Alarm {
1300                    sequence: control.regs.k,
1301                    details: AlarmDetails::ROUNDTUITAL {
1302                        explanation: "The emulator does not yet implement opcode JPA".to_string(),
1303                        bug_report_url: "https://github.com/TX-2/TX-2-simulator/issues/9",
1304                    },
1305                }),
1306                Opcode::Jna => Err(Alarm {
1307                    sequence: control.regs.k,
1308                    details: AlarmDetails::ROUNDTUITAL {
1309                        explanation: "The emulator does not yet implement opcode JNA".to_string(),
1310                        bug_report_url: "https://github.com/TX-2/TX-2-simulator/issues/10",
1311                    },
1312                }),
1313                Opcode::Exa => Err(Alarm {
1314                    sequence: control.regs.k,
1315                    details: AlarmDetails::ROUNDTUITAL {
1316                        explanation: "The emulator does not yet implement opcode EXA".to_string(),
1317                        bug_report_url: "https://github.com/TX-2/TX-2-simulator/issues/143",
1318                    },
1319                }),
1320                Opcode::Ins => Err(Alarm {
1321                    sequence: control.regs.k,
1322                    details: AlarmDetails::ROUNDTUITAL {
1323                        explanation: "The emulator does not yet implement opcode INS".to_string(),
1324                        bug_report_url: "https://github.com/TX-2/TX-2-simulator/issues/26",
1325                    },
1326                }),
1327                Opcode::Com => Err(Alarm {
1328                    sequence: control.regs.k,
1329                    details: AlarmDetails::ROUNDTUITAL {
1330                        explanation: "The emulator does not yet implement opcode COM".to_string(),
1331                        bug_report_url: "https://github.com/TX-2/TX-2-simulator/issues/27",
1332                    },
1333                }),
1334                Opcode::Cya | Opcode::Cyb | Opcode::Cab => Err(Alarm {
1335                    sequence: control.regs.k,
1336                    details: AlarmDetails::ROUNDTUITAL {
1337                        explanation: "The emulator does not yet implement opcode {opcode}"
1338                            .to_string(),
1339                        bug_report_url: "https://github.com/TX-2/TX-2-simulator/issues/24",
1340                    },
1341                }),
1342                Opcode::Noa => Err(Alarm {
1343                    sequence: control.regs.k,
1344                    details: AlarmDetails::ROUNDTUITAL {
1345                        explanation: "The emulator does not yet implement opcode NOA".to_string(),
1346                        bug_report_url: "https://github.com/TX-2/TX-2-simulator/issues/22",
1347                    },
1348                }),
1349                Opcode::Nab => Err(Alarm {
1350                    sequence: control.regs.k,
1351                    details: AlarmDetails::ROUNDTUITAL {
1352                        explanation: "The emulator does not yet implement opcode NAB".to_string(),
1353                        bug_report_url: "https://github.com/TX-2/TX-2-simulator/issues/23",
1354                    },
1355                }),
1356                Opcode::Add => Err(Alarm {
1357                    sequence: control.regs.k,
1358                    details: AlarmDetails::ROUNDTUITAL {
1359                        explanation: "The emulator does not yet implement opcode ADD".to_string(),
1360                        bug_report_url: "https://github.com/TX-2/TX-2-simulator/issues/28",
1361                    },
1362                }),
1363                Opcode::Sca => Err(Alarm {
1364                    sequence: control.regs.k,
1365                    details: AlarmDetails::ROUNDTUITAL {
1366                        explanation: "The emulator does not yet implement opcode SCA".to_string(),
1367                        bug_report_url: "https://github.com/TX-2/TX-2-simulator/issues/19",
1368                    },
1369                }),
1370                Opcode::Scb => Err(Alarm {
1371                    sequence: control.regs.k,
1372                    details: AlarmDetails::ROUNDTUITAL {
1373                        explanation: "The emulator does not yet implement opcode SCB".to_string(),
1374                        bug_report_url: "https://github.com/TX-2/TX-2-simulator/issues/20",
1375                    },
1376                }),
1377                Opcode::Sab => Err(Alarm {
1378                    sequence: control.regs.k,
1379                    details: AlarmDetails::ROUNDTUITAL {
1380                        explanation: "The emulator does not yet implement opcode SAB".to_string(),
1381                        bug_report_url: "https://github.com/TX-2/TX-2-simulator/issues/21",
1382                    },
1383                }),
1384                Opcode::Tly => Err(Alarm {
1385                    sequence: control.regs.k,
1386                    details: AlarmDetails::ROUNDTUITAL {
1387                        explanation: "The emulator does not yet implement opcode TLY".to_string(),
1388                        bug_report_url: "https://github.com/TX-2/TX-2-simulator/issues/32",
1389                    },
1390                }),
1391                Opcode::Div => Err(Alarm {
1392                    sequence: control.regs.k,
1393                    details: AlarmDetails::ROUNDTUITAL {
1394                        explanation: "The emulator does not yet implement opcode DIV".to_string(),
1395                        bug_report_url: "https://github.com/TX-2/TX-2-simulator/issues/31",
1396                    },
1397                }),
1398                Opcode::Mul => Err(Alarm {
1399                    sequence: control.regs.k,
1400                    details: AlarmDetails::ROUNDTUITAL {
1401                        explanation: "The emulator does not yet implement opcode MUL".to_string(),
1402                        bug_report_url: "https://github.com/TX-2/TX-2-simulator/issues/30",
1403                    },
1404                }),
1405                Opcode::Sub => Err(Alarm {
1406                    sequence: control.regs.k,
1407                    details: AlarmDetails::ROUNDTUITAL {
1408                        explanation: "The emulator does not yet implement opcode SUB".to_string(),
1409                        bug_report_url: "https://github.com/TX-2/TX-2-simulator/issues/29",
1410                    },
1411                }),
1412            }
1413        }
1414
1415        if self.select_sequence(mem) == RunMode::InLimbo {
1416            return Ok((0, RunMode::InLimbo, None));
1417        }
1418
1419        let seq_desc = match self.regs.k {
1420            None => "none".to_string(),
1421            Some(n) => format!("{n:02o}"),
1422        };
1423
1424        // Fetch the current instruction into the N register.
1425        {
1426            let span = span!(Level::INFO,
1427                             "fetch",
1428                             seq=%seq_desc,
1429                             p=?self.regs.p);
1430            let _enter = span.enter();
1431            self.fetch_instruction(ctx, mem)
1432                .map_err(|alarm| (alarm, self.regs.p))?;
1433        }
1434
1435        // Save the old program counter.
1436        let p = self.regs.p;
1437        self.set_program_counter(ProgramCounterChange::CounterUpdate);
1438
1439        let elapsed_time = self.estimate_execute_time_ns(&self.regs.n);
1440
1441        let result: Result<Option<OutputEvent>, (Alarm, Address)> =
1442            if let Some(sym) = self.regs.n_sym.as_ref() {
1443                let inst = sym.to_string();
1444                let span = span!(Level::INFO,
1445                                 "xop",
1446                                 seq=%seq_desc,
1447                                 p=?p,
1448                                 op=%sym.opcode());
1449                let _enter = span.enter();
1450                event!(Level::TRACE, "executing instruction {}", &sym);
1451                match execute(ctx, p, &sym.opcode(), self, devices, mem) {
1452                    Ok(opcode_result) => {
1453                        event!(
1454                            Level::TRACE,
1455                            "opcode_result.poll_order_change={:?}",
1456                            &opcode_result.poll_order_change
1457                        );
1458                        if let Some(seq) = opcode_result.poll_order_change {
1459                            *poll_order_change = Some(seq);
1460                            please_poll_soon(ctx, devices, seq);
1461                        }
1462                        match opcode_result.program_counter_change {
1463                            None => {
1464                                // This is the usual case; the call to
1465                                // set_program_counter above will have
1466                                // incremented P.
1467                            }
1468                            Some(pc_change) => {
1469                                // Instructions which return
1470                                // ProgramCounterChange::CounterUpdate do
1471                                // so in order perform a skip over the
1472                                // next instruction.
1473                                event!(Level::TRACE, "program counter change: {:?}", &pc_change);
1474                                self.set_program_counter(pc_change);
1475                            }
1476                        }
1477                        Ok(opcode_result.output)
1478                    }
1479                    Err(alarm) => {
1480                        event!(Level::WARN, "instruction {} raised alarm {}", inst, alarm);
1481                        match self
1482                            .alarm_unit
1483                            .fire_if_not_masked(alarm.clone(), &self.regs.diagnostic_only)
1484                        {
1485                            Err(alarm) => {
1486                                event!(
1487                                    Level::DEBUG,
1488                                    "execute_instruction: unmasked_alarm_active: {}",
1489                                    self.unmasked_alarm_active()
1490                                );
1491                                self.set_program_counter(ProgramCounterChange::Stop(p));
1492                                Err((alarm, p))
1493                            }
1494                            Ok(()) => {
1495                                // The alarm is active but masked.
1496                                event!(
1497                                    Level::DEBUG,
1498                                    "execute_instruction: alarm {:?} is active but masked",
1499                                    alarm
1500                                );
1501                                Ok(None) // no output event.
1502                            }
1503                        }
1504                    }
1505                }
1506            } else {
1507                event!(
1508                    Level::INFO,
1509                    "fetched instruction {:?} is invalid",
1510                    &self.regs.n
1511                );
1512                match self
1513                    .alarm_unit
1514                    .fire_if_not_masked(self.invalid_opcode_alarm(), &self.regs.diagnostic_only)
1515                {
1516                    Err(e) => {
1517                        self.set_program_counter(ProgramCounterChange::Stop(p));
1518                        Err((e, p))
1519                    }
1520                    Ok(()) => Ok(None),
1521                }
1522            };
1523
1524        // We have completed an attempt to execute instruction.  It
1525        // may not have been successful, so we cannot set the value of
1526        // prev_hold unconditionally. Determine whether this
1527        // instruction should be followed by a change of sequence.
1528        match result {
1529            Ok(maybe_output) => {
1530                let new_mode: RunMode = self.select_sequence(mem);
1531                Ok((elapsed_time, new_mode, maybe_output))
1532            }
1533            Err((alarm, address)) => Err((alarm, address)),
1534        }
1535        // self.regs.k now identifies the sequence we should be
1536        // running and self.regs.p contains its program counter.
1537    }
1538
1539    fn get_config(&self) -> SystemConfiguration {
1540        let cf = self.regs.n.configuration();
1541        self.regs.get_f_mem(cf)
1542    }
1543
1544    fn fetch_operand_from_address_with_exchange(
1545        &mut self,
1546        ctx: &Context,
1547        mem: &mut MemoryUnit,
1548        operand_address: &Address,
1549        existing_dest: &Unsigned36Bit,
1550        update_e: &UpdateE,
1551    ) -> Result<(Unsigned36Bit, ExtraBits), Alarm> {
1552        let (memword, extra) =
1553            self.fetch_operand_from_address_without_exchange(ctx, mem, operand_address, update_e)?;
1554        let exchanged = exchanged_value_for_load(&self.get_config(), &memword, existing_dest);
1555        Ok((exchanged, extra))
1556    }
1557
1558    fn fetch_operand_from_address_without_exchange(
1559        &mut self,
1560        ctx: &Context,
1561        mem: &mut MemoryUnit,
1562        operand_address: &Address,
1563        update_e: &UpdateE,
1564    ) -> Result<(Unsigned36Bit, ExtraBits), Alarm> {
1565        let meta_op: MetaBitChange = if self.trap.set_metabits_of_operands() {
1566            MetaBitChange::Set
1567        } else {
1568            MetaBitChange::None
1569        };
1570        match mem.fetch(ctx, operand_address, &meta_op) {
1571            Ok((word, extra_bits)) => {
1572                if extra_bits.meta && self.trap.trap_on_operand() {
1573                    self.raise_trap();
1574                }
1575                if let UpdateE::Yes = update_e {
1576                    mem.set_e_register(word);
1577                }
1578                Ok((word, extra_bits))
1579            }
1580            Err(MemoryOpFailure::NotMapped(addr)) => {
1581                self.alarm_unit.fire_if_not_masked(
1582                    Alarm {
1583                        sequence: self.regs.k,
1584                        details: AlarmDetails::QSAL(
1585                            self.regs.n,
1586                            BadMemOp::Read(Unsigned36Bit::from(addr)),
1587                            format!(
1588                                "memory unit indicated address {operand_address:o} is not mapped",
1589                            ),
1590                        ),
1591                    },
1592                    &self.regs.diagnostic_only,
1593                )?;
1594                // QSAL is masked to we have to return some value, but
1595                // we don't know what the TX-2 did in this case.
1596                Err(self.alarm_unit.always_fire(Alarm {
1597                    sequence: self.regs.k,
1598                    details: AlarmDetails::ROUNDTUITAL {
1599                        explanation: format!(
1600                        "memory unit indicated address {operand_address:o} is not mapped and we don't know what to do when QSAL is masked",
1601                        ),
1602                        // Note: there are two different ways in which
1603                        // we can raise a ROUNDTUITAL alarm referring
1604                        // to this bug report URL.
1605                        bug_report_url: "https://github.com/TX-2/TX-2-simulator/issues/142",
1606                    }
1607                }, &self.regs.diagnostic_only))
1608            }
1609            Err(MemoryOpFailure::ReadOnly(_, _)) => unreachable!(),
1610        }
1611    }
1612
1613    fn memory_store_without_exchange(
1614        &mut self,
1615        ctx: &Context,
1616        mem: &mut MemoryUnit,
1617        target: &Address,
1618        value: &Unsigned36Bit,
1619        update_e: &UpdateE,
1620        meta_op: &MetaBitChange,
1621    ) -> Result<(), Alarm> {
1622        event!(
1623            Level::TRACE,
1624            "memory_store_without_exchange: write @{:>06o} <- {:o}",
1625            target,
1626            value,
1627        );
1628        if let &UpdateE::Yes = update_e {
1629            // The E register gets updated to the value we want to
1630            // write, even if we cannot actually write it (see example
1631            // 10 on page 3-17 of the Users Handbook).
1632            mem.set_e_register(*value);
1633        }
1634        if let Err(e) = mem.store(ctx, target, value, meta_op) {
1635            self.alarm_unit.fire_if_not_masked(
1636                Alarm {
1637                    sequence: self.regs.k,
1638                    details: AlarmDetails::QSAL(
1639                        self.regs.n,
1640                        BadMemOp::Write(Unsigned36Bit::from(*target)),
1641                        format!("memory store to address {target:#o} failed: {e}",),
1642                    ),
1643                },
1644                &self.regs.diagnostic_only,
1645            )?;
1646            Ok(()) // QSAL is masked, so just carry on.
1647        } else {
1648            Ok(())
1649        }
1650    }
1651
1652    #[allow(clippy::too_many_arguments)]
1653    fn memory_store_with_exchange(
1654        &mut self,
1655        ctx: &Context,
1656        mem: &mut MemoryUnit,
1657        target: &Address,
1658        value: &Unsigned36Bit,
1659        existing: &Unsigned36Bit,
1660        update_e: &UpdateE,
1661        meta_op: &MetaBitChange,
1662    ) -> Result<(), Alarm> {
1663        self.memory_store_without_exchange(
1664            ctx,
1665            mem,
1666            target,
1667            &exchanged_value_for_store(&self.get_config(), value, existing),
1668            update_e,
1669            meta_op,
1670        )
1671    }
1672
1673    /// Determine the address of the operand for instructions that use
1674    /// indexing.
1675    fn operand_address_with_optional_defer_and_index(
1676        self: &mut ControlUnit,
1677        ctx: &Context,
1678        mem: &mut MemoryUnit,
1679    ) -> Result<Address, Alarm> {
1680        self.resolve_operand_address(ctx, mem, None)
1681    }
1682
1683    /// Determine the address of the operand for instructions that do
1684    /// not use indexing.
1685    fn operand_address_with_optional_defer_without_index(
1686        self: &mut ControlUnit,
1687        ctx: &Context,
1688        mem: &mut MemoryUnit,
1689    ) -> Result<Address, Alarm> {
1690        self.resolve_operand_address(ctx, mem, Some(Unsigned6Bit::ZERO))
1691    }
1692
1693    /// Resolve the address of the operand of the current instruction,
1694    /// leaving this address in the Q register.
1695    ///
1696    /// # Arguments
1697    ///
1698    /// * `ctx` - context data for the execution of the instruction.
1699    /// * `mem` - the memory unit (which we would use for deferred indexing).
1700    /// * `initial_index_override` - source of the j bits (index
1701    ///   register number) to be used; this is specified when processing
1702    ///   the `JNX` instruction for example.  If the value is `None`,
1703    ///   the value is instead taken from the N register.
1704    fn resolve_operand_address(
1705        self: &mut ControlUnit,
1706        ctx: &Context,
1707        mem: &mut MemoryUnit,
1708        initial_index_override: Option<Unsigned6Bit>,
1709    ) -> Result<Address, Alarm> {
1710        // The deferred addressing process may be performed more than
1711        // once, in other words it is a loop.  This is explained in
1712        // section 9-7, "DEFERRED ADDRESSING CYCLES" of Volume 2 of
1713        // the technical manual.
1714        //
1715        // See also "TX-2 Introductory Notes" by A. Vanderburgh, 24
1716        // February 1959, available from the UMN collection (BCI61 Box
1717        // 8).
1718        let mut seen_deferred_addresses: HashSet<Address> = HashSet::new();
1719        let physical_address: Address = loop {
1720            let (defer, physical) = self.regs.n.operand_address().split();
1721            if !defer {
1722                break physical;
1723            }
1724
1725            // In effect, this loop emulates a non-ultimate deferred
1726            // address cycle.
1727            //
1728            // According to the description of PK3 on page 5-9 of the
1729            // User handbook, the deferred address calculation and
1730            // indexing occurs in (i.e. by modifying) the N register.
1731            // "TX-2 Introductory Notes" explains the same thing.
1732            //
1733            // JPX and JNX seem to be handled differently, but I don't
1734            // think I understand exactly what the difference is
1735            // supposed to be. "TX-2 Introductory Notes" points out
1736            // that in JPX and JNX, the j bits are used for something
1737            // other than indexing, so the "handled differently" may
1738            // just be that deferred addressing is the only way to use
1739            // indexing in combination with JPX and JNX.
1740            //
1741            // (Vol 2, page 12-9): It should also be noted that the
1742            // N₂.₉ bit is presented as an input to the X Adder only
1743            // when no deferred address cycles are called for.  When
1744            // PI¹₂, the input to the X Adder from the N₂.₉ position
1745            // is forced to appear as a ZERO.
1746            event!(
1747                Level::TRACE,
1748                "deferred addressing: deferred address is {:o}",
1749                &physical
1750            );
1751            let meta_op = if self.trap.set_metabits_of_deferred_addresses() {
1752                MetaBitChange::Set
1753            } else {
1754                MetaBitChange::None
1755            };
1756            let fetched = match mem.fetch(ctx, &physical, &meta_op) {
1757                Err(e) => {
1758                    let msg = || {
1759                        format!(
1760                            "address {:#o} out of range while fetching deferred address: {}",
1761                            &physical, e
1762                        )
1763                    };
1764
1765                    self.alarm_unit.fire_if_not_masked(
1766                        Alarm {
1767                            sequence: self.regs.k,
1768                            details: AlarmDetails::QSAL(
1769                                self.regs.n,
1770                                BadMemOp::Read(Unsigned36Bit::from(physical)),
1771                                msg(),
1772                            ),
1773                        },
1774                        &self.regs.diagnostic_only,
1775                    )?;
1776                    // QSAL is masked.  I don't know what the TX-2 did in this situation.
1777                    return Err(self.alarm_unit.always_fire(
1778                        Alarm {
1779                            sequence: self.regs.k,
1780                            details: AlarmDetails::ROUNDTUITAL {
1781                                explanation: format!(
1782                                    "we don't know how to handle {} when QSAL is masked",
1783                                    msg()
1784                                ),
1785                                // Note: there are two different ways in
1786                                // which we can raise a ROUNDTUITAL alarm
1787                                // referring to this bug report URL.
1788                                bug_report_url: "https://github.com/TX-2/TX-2-simulator/issues/142",
1789                            },
1790                        },
1791                        &self.regs.diagnostic_only,
1792                    ));
1793                }
1794                Ok((word, extra)) => {
1795                    if extra.meta && self.trap.trap_on_deferred_address() {
1796                        self.raise_trap();
1797                    }
1798
1799                    // The TX2 performs indexation on deferred
1800                    // addreses.  Indeed, the "TX-2 Introductory
1801                    // Notes" by A. Vanderburg imply that the ability
1802                    // to do this is the motivation for having
1803                    // deferred addressing at all (see section
1804                    // "Deferred Addressing" in that document).
1805                    //
1806                    // This idea is also supported by the fact that
1807                    // the left subword of deferred addresses used in
1808                    // plugboard programs can be nonzero, and on the
1809                    // fact that the description of the SKM
1810                    // instruction notes "SKM is therefore
1811                    // non-indexable except through deferred
1812                    // addressing".
1813                    let (left, right) = subword::split_halves(word);
1814                    let mask: Unsigned18Bit = Unsigned18Bit::from(63_u8);
1815                    let j6: Unsigned6Bit = Unsigned6Bit::try_from(left.bitand(mask)).unwrap();
1816                    let next = Address::from(right).index_by(self.regs.get_index_register(j6));
1817                    event!(
1818                        Level::TRACE,
1819                        "deferred addressing: fetched full word is {:o},,{:o}; j={:o}, using {:o} as the next address",
1820                        &left,
1821                        &right,
1822                        &j6,
1823                        &next,
1824                    );
1825                    if !seen_deferred_addresses.insert(next) {
1826                        // A `false` return indicates that the map
1827                        // already contained `next`, meaning that we
1828                        // have a loop.
1829                        //
1830                        // Detection of this kind of loop is not a
1831                        // feature of the TX-2.  The "TX-2
1832                        // Introductory Notes" document explicitly
1833                        // states, "In fact, you can inadvertantly
1834                        // [sic] defer back to where you started and
1835                        // get a loop less than one instruction long".
1836                        return Err(self.alarm_unit.always_fire(
1837                            Alarm {
1838                                sequence: self.regs.k,
1839                                details: AlarmDetails::DEFERLOOPAL { address: right },
1840                            },
1841                            &self.regs.diagnostic_only,
1842                        ));
1843                    }
1844                    next
1845                }
1846            };
1847
1848            // We update the lower 18 bits (i.e. right half) of N with
1849            // the value we just loaded from memory.
1850            let unchanged_left = subword::left_half(Unsigned36Bit::from(self.regs.n));
1851            self.update_n_register(subword::join_halves(
1852                unchanged_left,
1853                Unsigned18Bit::from(fetched),
1854            ))?;
1855        };
1856
1857        // The defer bit in N is (now) not set.  Emulate a regular or
1858        // ultimate address cycle.  That is, add the index value to
1859        // the operand address.  While the index_address field in the
1860        // instruction is unsigned (following the conventions in the
1861        // assembly source), the indexation operation itself uses
1862        // signed arithmetic (see the explanation in the doc comment
1863        // for the IndexBy trait).
1864        let j = match initial_index_override {
1865            None => self.regs.n.index_address(),
1866            Some(overridden) => overridden,
1867        };
1868        let delta = self.regs.get_index_register(j); // this is Xj.
1869
1870        // A number of things expect that the "most recent data
1871        // (memory) reference" is saved in register Q.  `¹⁴JMP`
1872        // (a.k.a. `JPQ`) makes use of this, for example.
1873        self.regs.q = physical_address.index_by(delta);
1874
1875        // TODO: figure out if other parts of the system documentation
1876        // definitely expect the physical operand address to be
1877        // written back into the N register (in a
1878        // programmer-detectable way).
1879        //
1880        // "TX-2 Introductory Notes" states that this happens, but the
1881        // question is whether the programmer can detect it.
1882        Ok(self.regs.q)
1883    }
1884
1885    fn write_operand_metaop(&self) -> MetaBitChange {
1886        if self.trap.set_metabits_of_operands() {
1887            MetaBitChange::Set
1888        } else {
1889            MetaBitChange::None
1890        }
1891    }
1892
1893    fn memory_read_and_update_with_exchange<F>(
1894        &mut self,
1895        ctx: &Context,
1896        mem: &mut MemoryUnit,
1897        target: &Address,
1898        update_e: &UpdateE,
1899        transform: F,
1900    ) -> Result<(), Alarm>
1901    where
1902        F: FnOnce(Unsigned36Bit) -> Unsigned36Bit,
1903    {
1904        // We unconditionally perform the memory read.  But in the
1905        // real TX-2 there are cases where the read may not actually
1906        // need to happen.  For example the instruction `⁰STA T` is
1907        // implemented by a call to this function but does not need to
1908        // read from `target` although similar instructions might.
1909        // For example, `²STA T` modifies L(T) but not R(T) and so if
1910        // there were a hardware parity error affecting T, this
1911        // instruction would likely fail on the real hardware.
1912        match self.fetch_operand_from_address_without_exchange(ctx, mem, target, &UpdateE::No) {
1913            Ok((existing, _meta)) => {
1914                let newval = transform(existing);
1915                self.memory_store_with_exchange(
1916                    ctx,
1917                    mem,
1918                    target,
1919                    &newval,
1920                    &existing,
1921                    update_e,
1922                    &self.write_operand_metaop(),
1923                )
1924            }
1925            Err(Alarm {
1926                sequence: _,
1927                details: AlarmDetails::QSAL(inst, BadMemOp::Read(addr), msg),
1928            }) => {
1929                // That read operation just failed.  So we handle this
1930                // as a _write_ failure, meaning that we change
1931                // BadMemOp::Read to BadMemOp::Write.
1932                //
1933                // If fire_details_if_not_masked() returns (), QSAL is
1934                // masked, we just carry on (the `DPX` instruction has
1935                // no effect).
1936                self.fire_details_if_not_masked(AlarmDetails::QSAL(
1937                    inst,
1938                    BadMemOp::Write(addr),
1939                    msg,
1940                ))
1941            }
1942            Err(other) => Err(other),
1943        }
1944    }
1945
1946    fn dismiss(&mut self, reason: &str) {
1947        if let Some(current_seq) = self.regs.k {
1948            event!(
1949                Level::DEBUG,
1950                "dismissing current sequence {current_seq:o} (reason: {reason}) while executing instruction from {:o}",
1951                self.regs.diagnostic_only.instruction_address,
1952            );
1953            self.regs.flags.lower(&current_seq);
1954            self.regs.current_sequence_is_runnable = false;
1955        }
1956    }
1957
1958    fn dismiss_unless_held(&mut self, reason: &str) -> bool {
1959        if self.regs.n.is_held() {
1960            false
1961        } else {
1962            self.dismiss(reason);
1963            true
1964        }
1965    }
1966
1967    #[must_use]
1968    pub fn current_flag_state(&self, unit: &SequenceNumber) -> bool {
1969        self.regs.current_flag_state(unit)
1970    }
1971
1972    pub fn drain_alarm_changes(&mut self) -> BTreeMap<AlarmKind, AlarmStatus> {
1973        self.alarm_unit.drain_alarm_changes()
1974    }
1975
1976    pub fn drain_flag_changes(&mut self) -> Vec<(SequenceNumber, Signed18Bit)> {
1977        self.regs
1978            .flags
1979            .drain_flag_changes()
1980            .into_iter()
1981            .map(|seq| {
1982                let index_value: &Signed18Bit = self
1983                    .regs
1984                    .index_regs
1985                    .get(usize::from(seq))
1986                    .expect("sequences should all have valid index register values");
1987                (seq, *index_value)
1988            })
1989            .collect()
1990    }
1991
1992    #[must_use]
1993    pub fn inspect_registers(&self) -> &ControlRegisters {
1994        &self.regs
1995    }
1996}
1997
1998impl Default for ControlUnit {
1999    fn default() -> Self {
2000        Self::new(
2001            PanicOnUnmaskedAlarm::No,
2002            ConfigurationMemorySetup::Uninitialised,
2003        )
2004    }
2005}
2006
2007impl Alarmer for ControlUnit {
2008    fn fire_if_not_masked<F: DiagnosticFetcher>(
2009        &mut self,
2010        alarm_instance: Alarm,
2011        get_diags: F,
2012    ) -> Result<(), Alarm> {
2013        self.alarm_unit
2014            .fire_if_not_masked(alarm_instance, get_diags)
2015    }
2016
2017    fn always_fire<F: DiagnosticFetcher>(&mut self, alarm_instance: Alarm, get_diags: F) -> Alarm {
2018        self.alarm_unit.always_fire(alarm_instance, get_diags)
2019    }
2020}