cpu/control/
trap.rs

1//! Emulates the trap circuit and I/O Unit 42.  See TX-2 User Handbook
2//! Chapter 4 section 42.
3use std::fmt::Write;
4
5use base::prelude::*;
6use std::time::Duration;
7
8use crate::diagnostics::CurrentInstructionDiagnostics;
9
10use super::super::context::Context;
11use super::super::event::InputEvent;
12use super::super::io::{InputFlagRaised, TransferFailed, Unit, UnitStatus};
13use super::super::*;
14
15#[derive(Debug)]
16pub(crate) struct TrapCircuit {
17    mode: Unsigned12Bit,
18    set_metabits_disabled: bool,
19}
20
21impl TrapCircuit {
22    /// When this bit is set in `mode`, fetching an instruction word
23    /// whose metabit is set causes a trap to occur.
24    const TRAP_ON_MARKED_INSTRUCTION: Unsigned12Bit = Unsigned12Bit::MAX.and(0o000_001_u16);
25
26    /// When this bit is set in `mode`, an instruction cycle which
27    /// uses a marked deferred address causes the TRAP flag to be
28    /// raised.
29    const TRAP_ON_DEFERRED_ADDRESS: Unsigned12Bit = Unsigned12Bit::MAX.and(0o000_002_u16);
30
31    /// When this bit is set in `mode`, use of a marked operand causes
32    /// the TRAP flag to be raised soon afterward (within a few
33    /// instructions).
34    const TRAP_ON_OPERAND: Unsigned12Bit = Unsigned12Bit::MAX.and(0o000_004_u16);
35
36    /// When this bit is set, change of sequence number causes the
37    /// TRAP flag to be raised.  Change of sequence away from sequence
38    /// 0o42 (the TRAP sequence itself) does not cause the flag to be
39    /// raised).
40    const TRAP_ON_CHANGED_SEQUENCE: Unsigned12Bit = Unsigned12Bit::MAX.and(0o000_010_u16);
41
42    /// When this bit is set, fetching an instruction from a memory
43    /// word causes the meta bit of that word to be set.
44    const SET_METABITS_OF_INSTRUCTIONS: Unsigned12Bit = Unsigned12Bit::MAX.and(0o000_100_u16);
45
46    /// When this bit is set, the metabit of all deferred addresses used will be set.
47    const SET_METABITS_OF_DEFERRED_ADDRESSES: Unsigned12Bit = Unsigned12Bit::MAX.and(0o000_200_u16);
48
49    /// When this bit is set, the metabits of memory words containing operands will be set.
50    const SET_METABITS_OF_OPERANDS: Unsigned12Bit = Unsigned12Bit::MAX.and(0o000_400_u16);
51
52    pub(crate) const fn new() -> TrapCircuit {
53        TrapCircuit {
54            mode: Unsigned12Bit::ZERO,
55            set_metabits_disabled: false,
56        }
57    }
58
59    /// Query the hardware switch setting which would disable all
60    /// setting of metabits.
61    pub(crate) fn is_set_metabits_disabled(&self) -> bool {
62        self.set_metabits_disabled
63    }
64
65    /// Change the (emulated) hardware switch setting which (when
66    /// `disable` is true) would disable all setting of metabits.
67    pub(crate) fn set_metabits_disabled(&mut self, disable: bool) {
68        self.set_metabits_disabled = disable;
69    }
70
71    /// Indicate whether the machine should set the metabits of words
72    /// from which it fetches instructions.
73    pub(crate) fn set_metabits_of_instructions(&self) -> bool {
74        !self.is_set_metabits_disabled() && self.mode & Self::SET_METABITS_OF_INSTRUCTIONS != 0
75    }
76
77    /// Indicate whether the machine should set the metabits of words
78    /// from which it fetches deferred addresses.
79    pub(crate) fn set_metabits_of_deferred_addresses(&self) -> bool {
80        !self.is_set_metabits_disabled()
81            && self.mode & Self::SET_METABITS_OF_DEFERRED_ADDRESSES != 0
82    }
83
84    /// Indicate whether the machine should set the metabits of words
85    /// from which it fetches operands.
86    pub(crate) fn set_metabits_of_operands(&self) -> bool {
87        !self.is_set_metabits_disabled() && self.mode & Self::SET_METABITS_OF_OPERANDS != 0
88    }
89
90    /// Indicate whether the TRAP flag should be raised during
91    /// execution of an instruction whose metabit is set.
92    pub(crate) fn trap_on_marked_instruction(&self) -> bool {
93        self.mode & Self::TRAP_ON_MARKED_INSTRUCTION != 0
94    }
95
96    /// Indicate whether an instruction cycle which uses a marked
97    /// deferred address causes the TRAP flag to be raised.
98    pub(crate) fn trap_on_deferred_address(&self) -> bool {
99        self.mode & Self::TRAP_ON_DEFERRED_ADDRESS != 0
100    }
101
102    /// Indicate whether use of a marked operand causes the TRAP flag
103    /// to be raised soon afterward (within a few instructions).
104    pub(crate) fn trap_on_operand(&self) -> bool {
105        self.mode & Self::TRAP_ON_OPERAND != 0
106    }
107
108    /// Indicate whether change of sequence number causes the TRAP
109    /// flag to be raised.  Change of sequence away from sequence 0o42
110    /// (the TRAP sequence itself) does not cause the flag to be
111    /// raised).
112    pub(crate) fn trap_on_changed_sequence(&self) -> bool {
113        self.mode & Self::TRAP_ON_CHANGED_SEQUENCE != 0
114    }
115}
116
117impl Unit for TrapCircuit {
118    fn poll(&mut self, ctx: &Context) -> UnitStatus {
119        UnitStatus {
120            special: Unsigned12Bit::ZERO,
121            change_flag: None,
122            buffer_available_to_cpu: false,
123            inability: false,
124            missed_data: false,
125            mode: self.mode,
126            // The trap circuit does not need to be polled.
127            poll_after: ctx.simulated_time + Duration::from_secs(60),
128            is_input_unit: true,
129        }
130    }
131
132    fn connect(&mut self, _ctx: &Context, mode: Unsigned12Bit) {
133        self.mode = mode;
134    }
135
136    fn transfer_mode(&self) -> TransferMode {
137        TransferMode::Exchange
138    }
139
140    /// The TRAP unit doesn't perform I/O but reads retain the
141    /// cycle-left and dismiss features (See Users Handbook, section
142    /// 4-15 ("TRAP").  Because it cycles left, it must be an "input"
143    /// unit.
144    fn read(
145        &mut self,
146        _ctx: &Context,
147        _diags: &CurrentInstructionDiagnostics,
148    ) -> Result<MaskedWord, TransferFailed> {
149        // TODO: add unit tests for the cycle-left and dismiss
150        // behaviours.
151        Ok(MaskedWord {
152            bits: Unsigned36Bit::ZERO,
153            mask: Unsigned36Bit::ZERO,
154        })
155    }
156
157    /// I don't know whether this is supposed to behave like an input
158    /// unit or an output unit.
159    fn write(
160        &mut self,
161        _ctx: &Context,
162        _source: Unsigned36Bit,
163        _diags: &CurrentInstructionDiagnostics,
164    ) -> Result<Option<OutputEvent>, TransferFailed> {
165        unreachable!()
166    }
167
168    fn name(&self) -> String {
169        "trap circuit".to_string()
170    }
171
172    fn disconnect(&mut self, _ctx: &Context) {
173        // Does nothing.
174    }
175
176    fn on_input_event(
177        &mut self,
178        _ctx: &Context,
179        _event: InputEvent,
180    ) -> Result<InputFlagRaised, InputEventError> {
181        // Does nothing.
182        Ok(InputFlagRaised::No)
183    }
184
185    fn text_info(&self, _ctx: &Context) -> String {
186        const STRING_WRITE_SUCCESS: &str = "write! calls on a String should always succeed";
187        let mut result = String::new();
188
189        if self.is_set_metabits_disabled() {
190            result.push_str("Set-metabits is disabled. ");
191        } else {
192            let mut metabit_setting_text: Vec<&str> = Vec::new();
193            if self.set_metabits_of_instructions() {
194                metabit_setting_text.push("instructions");
195            }
196            if self.set_metabits_of_deferred_addresses() {
197                metabit_setting_text.push("deferred addresses");
198            }
199            if self.set_metabits_of_operands() {
200                metabit_setting_text.push("operands");
201            }
202            if metabit_setting_text.is_empty() {
203                result.push_str("No metabits will be set. ");
204            } else {
205                write!(
206                    result,
207                    "Setting metabits for {}. ",
208                    metabit_setting_text.join(", ")
209                )
210                .expect(STRING_WRITE_SUCCESS);
211            }
212        }
213        let mut trap_on_text: Vec<&str> = Vec::new();
214        if self.trap_on_marked_instruction() {
215            trap_on_text.push("marked instruction");
216        }
217        if self.trap_on_deferred_address() {
218            trap_on_text.push("deferred address");
219        }
220        if self.trap_on_deferred_address() {
221            trap_on_text.push("operand");
222        }
223        if self.trap_on_changed_sequence() {
224            trap_on_text.push("sequence change");
225        }
226        if trap_on_text.is_empty() {
227            result.push_str("No traps are active. ");
228        } else {
229            write!(result, "Trap on {}. ", trap_on_text.join(", ")).expect(STRING_WRITE_SUCCESS);
230        }
231        result
232    }
233}