1use base::prelude::*;
3use base::subword;
4
5use super::super::UpdateE;
6use super::super::alarm::{Alarm, AlarmDetails, Alarmer, BadMemOp, BugActivity};
7use super::super::context::Context;
8use super::super::control::{ControlUnit, OpcodeResult, ProgramCounterChange};
9use super::super::diagnostics::CurrentInstructionDiagnostics;
10use super::super::exchanger::exchanged_value_for_load_without_sign_extension;
11use super::super::memory::{BitChange, MemoryMapped, MemoryOpFailure, MemoryUnit, WordChange};
12
13impl ControlUnit {
15 pub(crate) fn op_jmp(
17 &mut self,
18 _ctx: &Context,
19 mem: &mut MemoryUnit,
20 ) -> Result<OpcodeResult, Alarm> {
21 fn nonzero(value: Unsigned5Bit) -> bool {
25 !value.is_zero()
26 }
27 let cf = self.regs.n.configuration();
28 let save_q = nonzero(cf & 0b01000_u8);
29 let savep_e = nonzero(cf & 0b00100_u8);
30 let savep_ix = nonzero(cf & 0b00010_u8);
31 let indexed = nonzero(cf & 0b00001_u8);
32 let j = self.regs.n.index_address();
33 let left: Unsigned18Bit = if save_q {
34 Unsigned18Bit::from(self.regs.q)
35 } else {
36 subword::left_half(mem.get_e_register())
37 };
38 let right: Unsigned18Bit = if savep_e {
39 Unsigned18Bit::from(self.regs.p)
40 } else {
41 subword::right_half(mem.get_e_register())
42 };
43 mem.set_e_register(subword::join_halves(left, right));
44
45 let (deferred, physical) = self.regs.n.operand_address().split();
46 if deferred {
47 self.alarm_unit.fire_if_not_masked(
52 Alarm {
53 sequence: self.regs.k,
54 details: AlarmDetails::PSAL(
55 u32::from(self.regs.n.operand_address_and_defer_bit()),
56 format!(
57 "JMP target has deferred address {:#o}",
58 self.regs.n.operand_address()
59 ),
60 ),
61 },
62 &self.regs.diagnostic_only,
63 )?;
64 return Err(self.alarm_unit.always_fire(
67 Alarm {
68 sequence: self.regs.k,
69 details: AlarmDetails::ROUNDTUITAL {
70 explanation: "deferred JMP is not yet implemented".to_string(),
71 bug_report_url: "https://github.com/TX-2/TX-2-simulator/issues/141",
72 },
73 },
74 &self.regs.diagnostic_only,
75 ));
76 }
77
78 let new_pc: Address = if indexed {
79 physical.index_by(self.regs.get_index_register(j))
80 } else {
81 physical
82 };
83
84 if savep_ix && j != Unsigned6Bit::ZERO {
87 let p = self.regs.p;
88 self.regs.set_index_register_from_address(j, &p);
89 }
90
91 if nonzero(cf & 0b10000_u8) {
92 self.dismiss_unless_held("JMP has dismiss bit set in config syllable");
93 }
94 Ok(OpcodeResult {
95 program_counter_change: Some(ProgramCounterChange::Jump(new_pc)),
96 poll_order_change: None,
97 output: None,
98 })
99 }
100
101 pub(crate) fn op_skm(
111 &mut self,
112 ctx: &Context,
113 mem: &mut MemoryUnit,
114 ) -> Result<OpcodeResult, Alarm> {
115 let bit = index_address_to_bit_selection(self.regs.n.index_address());
116 let target = self.resolve_operand_address(ctx, mem, Some(Unsigned6Bit::ZERO))?;
120 let cf: u8 = u8::from(self.regs.n.configuration());
121 let change: WordChange = WordChange {
122 bit,
123 bitop: match cf & 0b11 {
124 0b00 => None,
125 0b01 => Some(BitChange::Flip),
126 0b10 => Some(BitChange::Clear),
127 0b11 => Some(BitChange::Set),
128 _ => unreachable!(),
129 },
130 cycle: cf & 0b100 != 0,
131 };
132 let prev_bit_value: Option<bool> = match mem.change_bit(ctx, &target, &change) {
133 Ok(prev) => prev,
134 Err(MemoryOpFailure::NotMapped(addr)) => {
135 self.alarm_unit.fire_if_not_masked(Alarm {
136 sequence: self.regs.k,
137 details: AlarmDetails::QSAL(
138 self.regs.n,
139 BadMemOp::Write(target.into()),
140 format!(
141 "SKM instruction attempted to access address {addr:o} but it is not mapped",
142 ),
143 ),
144 }, &self.regs.diagnostic_only)?;
145 return Ok(OpcodeResult::default());
147 }
148 Err(MemoryOpFailure::ReadOnly(_, _)) => {
149 self.alarm_unit.fire_if_not_masked(
150 Alarm {
151 sequence: self.regs.k,
152 details: AlarmDetails::QSAL(
153 self.regs.n,
154 BadMemOp::Write(target.into()),
155 format!(
156 "SKM instruction attempted to modify (instruction configuration={cf:o}) a read-only location {target:o}",
157 ),
158 )
159 }, &self.regs.diagnostic_only)?;
160 return Ok(OpcodeResult::default());
162 }
163 };
164 let skip: bool = if let Some(prevbit) = prev_bit_value {
165 match (cf >> 3) & 3 {
166 0b00 => false,
167 0b01 => true,
168 0b10 => !prevbit,
169 0b11 => prevbit,
170 _ => unreachable!(),
171 }
172 } else {
173 false
176 };
177 Ok(OpcodeResult {
178 program_counter_change: if skip {
183 Some(ProgramCounterChange::CounterUpdate)
184 } else {
185 None
186 },
187 poll_order_change: None,
188 output: None,
189 })
190 }
191
192 pub(crate) fn op_sed(
195 &mut self,
196 ctx: &Context,
197 mem: &mut MemoryUnit,
198 ) -> Result<OpcodeResult, Alarm> {
199 let existing_e_value = mem.get_e_register();
200 let target: Address = self.operand_address_with_optional_defer_and_index(ctx, mem)?;
201 let (mut word, _extra) =
205 self.fetch_operand_from_address_without_exchange(ctx, mem, &target, &UpdateE::No)?;
206 if mem.get_e_register() != existing_e_value {
207 let diags: CurrentInstructionDiagnostics = self.regs.diagnostic_only.clone();
208 return Err(self.always_fire(
209 Alarm {
210 sequence: self.regs.k,
211 details: AlarmDetails::BUGAL {
212 activity: BugActivity::Opcode,
213 diagnostics: diags.clone(),
214 message: "memory fetch during execution of SED changed the E register"
215 .to_string(),
216 },
217 },
218 &diags,
219 ));
220 }
221
222 word = exchanged_value_for_load_without_sign_extension(
226 &self.get_config(),
227 &word,
228 &mem.get_e_register(),
229 );
230
231 Ok(OpcodeResult {
232 program_counter_change: if word == mem.get_e_register() {
233 None
234 } else {
235 Some(ProgramCounterChange::CounterUpdate)
240 },
241 poll_order_change: None,
242 output: None,
243 })
244 }
245}
246
247#[cfg(test)]
248mod tests {
249 use super::super::super::alarm::Alarm;
250 use super::super::super::context::Context;
251 use super::super::super::control::{
252 ConfigurationMemorySetup, OpcodeResult, PanicOnUnmaskedAlarm, ProgramCounterChange, UpdateE,
253 };
254 use super::super::super::memory::MetaBitChange;
255 use super::super::super::{ControlUnit, MemoryConfiguration, MemoryUnit};
256 use base::instruction::{Opcode, SymbolicInstruction};
257 use base::prelude::*;
258 use core::time::Duration;
259
260 fn make_ctx() -> Context {
261 Context {
262 simulated_time: Duration::new(42, 42),
263 real_elapsed_time: Duration::new(7, 12),
264 }
265 }
266
267 fn setup(
268 ctx: &Context,
269 j: Unsigned6Bit,
270 initial: Signed18Bit,
271 e: Unsigned36Bit,
272 p: Address,
273 q: Address,
274 ) -> (ControlUnit, MemoryUnit) {
275 let mut control = ControlUnit::new(
276 PanicOnUnmaskedAlarm::Yes,
277 ConfigurationMemorySetup::StandardForTestingOnly,
278 );
279 let mut mem = MemoryUnit::new(
280 ctx,
281 &MemoryConfiguration {
282 with_u_memory: false,
283 },
284 );
285 if j == Unsigned6Bit::ZERO {
286 assert_eq!(initial, 0, "Cannot set X₀ to a nonzero value");
287 } else {
288 control.regs.set_index_register(j, &initial);
289 }
290 mem.set_e_register(e);
291 control.regs.p = p;
292 control.regs.q = q;
293 control.regs.k = Some(Unsigned6Bit::ZERO);
294 control.regs.flags.lower_all();
295 control.regs.flags.raise(&SequenceNumber::ZERO);
296 (control, mem)
297 }
298
299 fn simulate_jmp(
301 ctx: &Context,
302 j: Unsigned6Bit,
303 initial: Signed18Bit,
304 e: Unsigned36Bit,
305 p: Address,
306 q: Address,
307 inst: &SymbolicInstruction,
308 ) -> (Address, Signed18Bit, Unsigned36Bit, bool) {
309 const COMPLAIN: &str = "failed to set up JMP test data";
310 let (mut control, mut mem) = setup(ctx, j, initial, e, p, q);
311 control
312 .update_n_register(Instruction::from(inst).bits())
313 .expect(COMPLAIN);
314 let result = control.op_jmp(ctx, &mut mem);
315 match result {
316 Err(e) => {
317 panic!("JMP instruction failed: {e}");
318 }
319 Ok(OpcodeResult {
320 program_counter_change: Some(ProgramCounterChange::Jump(to)),
321 poll_order_change: None,
322 output: None,
323 }) => {
324 let xj = control.regs.get_index_register(j);
325 let dismissed = !control.regs.flags.current_flag_state(&SequenceNumber::ZERO);
326 (to, xj, mem.get_e_register(), dismissed)
327 }
328 other => {
329 panic!("JMP didn't jump in the expected way: {other:?}");
330 }
331 }
332 }
333
334 #[test]
337 fn test_jmp_example_1_jmp() {
338 let context = make_ctx();
339 let expected_target = Address::from(u18!(0o3733));
340 let orig_xj = Signed18Bit::from(20_i8);
341 let orig_e = u36!(0o606_202_333_123);
342 let (target, xj, e, dismissed) = simulate_jmp(
343 &context,
344 u6!(1),
345 orig_xj,
346 orig_e,
347 Address::from(u18!(0o1000)),
348 Address::from(u18!(0o2777)),
349 &SymbolicInstruction {
350 held: false,
351 configuration: Unsigned5Bit::ZERO, opcode: Opcode::Jmp,
353 index: u6!(1),
354 operand_address: OperandAddress::direct(expected_target),
355 },
356 );
357 assert_eq!(target, expected_target);
360 assert_eq!(xj, orig_xj); assert_eq!(e, orig_e); assert!(!dismissed);
363 }
364
365 #[test]
368 fn test_jmp_example_2_brc() {
369 let context = make_ctx();
370 let target_base = Address::from(u18!(0o3702));
371 let orig_xj = Signed18Bit::from(0o20_i8);
372 let orig_e = u36!(0o606_202_333_123);
373 let (target, xj, e, dismissed) = simulate_jmp(
374 &context,
375 u6!(1),
376 orig_xj,
377 orig_e,
378 Address::from(u18!(0o1000)), Address::from(u18!(0o2777)), &SymbolicInstruction {
381 held: false,
382 configuration: u5!(1), opcode: Opcode::Jmp,
384 index: u6!(1),
385 operand_address: OperandAddress::direct(target_base),
386 },
387 );
388 assert_eq!(target, Address::from(u18!(0o3722)));
390 assert_eq!(xj, orig_xj); assert_eq!(e, orig_e); assert!(!dismissed);
393 }
394
395 #[test]
398 fn test_jmp_example_3_jps() {
399 let context = make_ctx();
400 let target_base = Address::from(u18!(0o3702));
401 let orig_xj = Signed18Bit::from(0o20_i8);
402 let orig_e = u36!(0o606_202_333_123);
403 let (target, xj, e, dismissed) = simulate_jmp(
404 &context,
405 u6!(1),
406 orig_xj,
407 orig_e,
408 Address::from(u18!(0o1000)), Address::from(u18!(0o2777)), &SymbolicInstruction {
411 held: false,
412 configuration: u5!(2), opcode: Opcode::Jmp,
414 index: u6!(1),
415 operand_address: OperandAddress::direct(target_base),
416 },
417 );
418 assert_eq!(target, target_base);
420 assert_eq!(xj, u18!(0o1000).reinterpret_as_signed()); assert_eq!(e, orig_e); assert!(!dismissed);
423 }
424
425 #[test]
428 fn test_jmp_example_4_brs() {
429 let context = make_ctx();
430 let target_base = Address::from(u18!(0o3302));
431 let orig_xj = Signed18Bit::from(0o20_i8);
432 let orig_e = u36!(0o606_202_333_123);
433 let (target, xj, e, dismissed) = simulate_jmp(
434 &context,
435 u6!(1), orig_xj, orig_e, Address::from(u18!(0o200)), Address::from(u18!(0o2777)), &SymbolicInstruction {
441 held: false,
442 configuration: u5!(3), opcode: Opcode::Jmp,
444 index: u6!(1),
445 operand_address: OperandAddress::direct(target_base),
446 },
447 );
448 let expected_target = target_base.index_by(orig_xj);
450 assert_eq!(target, expected_target);
451 assert_eq!(xj, u18!(0o200).reinterpret_as_signed()); assert_eq!(e, orig_e); assert!(!dismissed);
454 }
455
456 #[test]
459 fn test_jmp_example_5() {
460 let context = make_ctx();
461 let target_base = Address::from(u18!(0o3302));
462 let orig_xj = Signed18Bit::from(0o20_i8);
463 let orig_e = u36!(0o606_202_333_123);
464 let (target, xj, e, dismissed) = simulate_jmp(
465 &context,
466 u6!(1), orig_xj, orig_e, Address::from(u18!(0o200)), Address::from(u18!(0o2777)), &SymbolicInstruction {
472 held: false,
473 configuration: u5!(4),
474 opcode: Opcode::Jmp,
475 index: u6!(1),
476 operand_address: OperandAddress::direct(target_base),
477 },
478 );
479 assert_eq!(target, target_base);
481 assert_eq!(xj, orig_xj); assert_eq!(e, join_halves(left_half(orig_e), u18!(0o200))); assert!(!dismissed);
484 }
485
486 #[test]
489 fn test_jmp_example_6_brc() {
490 let context = make_ctx();
491 let target_base = Address::from(u18!(0o3302));
492 let orig_xj = Signed18Bit::from(0o20_i8);
493 let orig_e = u36!(0o606_202_333_123);
494 let (target, xj, e, dismissed) = simulate_jmp(
495 &context,
496 u6!(1), orig_xj, orig_e, Address::from(u18!(0o200)), Address::from(u18!(0o2777)), &SymbolicInstruction {
502 held: false,
503 configuration: u5!(5), opcode: Opcode::Jmp,
505 index: u6!(1),
506 operand_address: OperandAddress::direct(target_base),
507 },
508 );
509 assert_eq!(target, Address::from(u18!(0o3322)));
511 assert_eq!(xj, orig_xj); assert_eq!(e, join_halves(left_half(orig_e), u18!(0o200))); assert!(!dismissed);
514 }
515
516 #[test]
519 fn test_jmp_example_7_jps() {
520 let context = make_ctx();
521 let target_base = Address::from(u18!(0o3302));
522 let orig_xj = Signed18Bit::from(0o20_i8);
523 let orig_e = u36!(0o606_202_333_123);
524 let (target, xj, e, dismissed) = simulate_jmp(
525 &context,
526 u6!(1), orig_xj, orig_e, Address::from(u18!(0o200)), Address::from(u18!(0o2777)), &SymbolicInstruction {
532 held: false,
533 configuration: u5!(6), opcode: Opcode::Jmp,
535 index: u6!(1),
536 operand_address: OperandAddress::direct(target_base),
537 },
538 );
539 assert_eq!(target, Address::from(u18!(0o3302)));
541 assert_eq!(xj, u18!(0o200).reinterpret_as_signed()); assert_eq!(e, join_halves(left_half(orig_e), u18!(0o200))); assert!(!dismissed);
544 }
545
546 #[test]
549 fn test_jmp_example_8_brs() {
550 let context = make_ctx();
551 let target_base = Address::from(u18!(0o3302));
552 let orig_xj = Signed18Bit::from(0o20_i8);
553 let orig_e = u36!(0o606_202_333_123);
554 let (target, xj, e, dismissed) = simulate_jmp(
555 &context,
556 u6!(1), orig_xj, orig_e, Address::from(u18!(0o200)), Address::from(u18!(0o2777)), &SymbolicInstruction {
562 held: false,
563 configuration: u5!(7), opcode: Opcode::Jmp,
565 index: u6!(1),
566 operand_address: OperandAddress::direct(target_base),
567 },
568 );
569 assert_eq!(target, Address::from(u18!(0o3322)));
572 assert_eq!(xj, u18!(0o200).reinterpret_as_signed()); assert_eq!(e, join_halves(left_half(orig_e), u18!(0o200))); assert!(!dismissed);
575 }
576
577 #[test]
580 fn test_jmp_example_9() {
581 let context = make_ctx();
582 let target_base = Address::from(u18!(0o3302));
583 let orig_xj = Signed18Bit::from(0o20_i8);
584 let orig_e = u36!(0o606_202_333_123);
585 let orig_q = u18!(0o2777);
586
587 let (target, xj, e, dismissed) = simulate_jmp(
588 &context,
589 u6!(1), orig_xj, orig_e, Address::from(u18!(0o200)), Address::from(orig_q), &SymbolicInstruction {
595 held: false,
596 configuration: u5!(0o10),
597 opcode: Opcode::Jmp,
598 index: u6!(1),
599 operand_address: OperandAddress::direct(target_base),
600 },
601 );
602 assert_eq!(target, Address::from(u18!(0o3302)));
605 assert_eq!(xj, orig_xj); assert_eq!(e, join_halves(orig_q, right_half(orig_e))); assert!(!dismissed);
608 }
609
610 #[test]
613 fn test_jmp_example_10_jpq() {
614 let context = make_ctx();
615 let target_base = Address::from(u18!(0o3302));
616 let orig_xj = Signed18Bit::from(0o20_i8);
617 let orig_e = u36!(0o606_202_333_123);
618 let orig_q = u18!(0o2777);
619 let orig_p = u18!(0o200);
620 let (target, xj, e, dismissed) = simulate_jmp(
621 &context,
622 u6!(1), orig_xj, orig_e, Address::from(orig_p), Address::from(orig_q), &SymbolicInstruction {
628 held: false,
629 configuration: u5!(0o14), opcode: Opcode::Jmp,
631 index: u6!(1),
632 operand_address: OperandAddress::direct(target_base),
633 },
634 );
635 assert_eq!(target, Address::from(u18!(0o3302)));
639 assert_eq!(xj, orig_xj); assert_eq!(e, join_halves(orig_q, orig_p)); assert!(!dismissed);
642 }
643
644 #[test]
647 fn test_jmp_example_11_bpq() {
648 let context = make_ctx();
649 let target_base = Address::from(u18!(0o3302));
650 let orig_xj = Signed18Bit::from(0o20_i8);
651 let orig_e = u36!(0o606_202_333_123);
652 let orig_q = u18!(0o2777);
653 let orig_p = u18!(0o200);
654 let (target, xj, e, dismissed) = simulate_jmp(
655 &context,
656 u6!(1), orig_xj, orig_e, Address::from(orig_p), Address::from(orig_q), &SymbolicInstruction {
662 held: false,
663 configuration: u5!(0o15), opcode: Opcode::Jmp,
665 index: u6!(1),
666 operand_address: OperandAddress::direct(target_base),
667 },
668 );
669 assert_eq!(target, Address::from(u18!(0o3322)));
673 assert_eq!(xj, orig_xj); assert_eq!(e, join_halves(orig_q, orig_p)); assert!(!dismissed);
676 }
677
678 #[test]
681 fn test_jmp_example_12_jes() {
682 let context = make_ctx();
683 let target_base = Address::from(u18!(0o3302));
684 let orig_xj = Signed18Bit::from(0o20_i8);
685 let orig_e = u36!(0o606_202_333_123);
686 let orig_q = u18!(0o2777);
687 let orig_p = u18!(0o200);
688 let (target, xj, e, dismissed) = simulate_jmp(
689 &context,
690 u6!(1), orig_xj, orig_e, Address::from(orig_p), Address::from(orig_q), &SymbolicInstruction {
696 held: false,
697 configuration: u5!(0o16),
698 opcode: Opcode::Jmp,
699 index: u6!(1),
700 operand_address: OperandAddress::direct(target_base),
701 },
702 );
703 assert_eq!(target, Address::from(u18!(0o3302)));
705 assert_eq!(xj, orig_p.reinterpret_as_signed()); assert_eq!(e, join_halves(orig_q, orig_p)); assert!(!dismissed);
708 }
709
710 #[test]
713 fn test_jmp_example_13() {
714 let context = make_ctx();
715 let target_base = Address::from(u18!(0o3302));
716 let orig_xj = Signed18Bit::from(0o20_i8);
717 let orig_e = u36!(0o606_202_333_123);
718 let orig_q = u18!(0o2777);
719 let orig_p = u18!(0o200);
720 let (target, xj, e, dismissed) = simulate_jmp(
721 &context,
722 u6!(1), orig_xj, orig_e, Address::from(orig_p), Address::from(orig_q), &SymbolicInstruction {
728 held: false,
729 configuration: u5!(0o20),
730 opcode: Opcode::Jmp,
731 index: u6!(1),
732 operand_address: OperandAddress::direct(target_base),
733 },
734 );
735 assert_eq!(target, Address::from(u18!(0o3302)));
737 assert_eq!(xj, orig_xj); assert_eq!(e, orig_e); assert!(dismissed); }
741
742 #[test]
745 fn test_jmp_example_14() {
746 let context = make_ctx();
747 let target_base = Address::from(u18!(0o3302));
748 let orig_xj = Signed18Bit::from(0o20_i8);
749 let orig_e = u36!(0o606_202_333_123);
750 let orig_q = u18!(0o2777);
751 let orig_p = u18!(0o200);
752 let (target, xj, e, dismissed) = simulate_jmp(
753 &context,
754 u6!(1), orig_xj, orig_e, Address::from(orig_p), Address::from(orig_q), &SymbolicInstruction {
760 held: false,
761 configuration: u5!(0o21),
762 opcode: Opcode::Jmp,
763 index: u6!(1),
764 operand_address: OperandAddress::direct(target_base),
765 },
766 );
767 assert_eq!(target, Address::from(u18!(0o3322)));
769 assert_eq!(xj, orig_xj); assert_eq!(e, orig_e); assert!(dismissed); }
773
774 #[test]
777 fn test_jmp_example_15() {
778 let context = make_ctx();
779 let target_base = Address::from(u18!(0o3302));
780 let orig_xj = Signed18Bit::from(0o20_i8);
781 let orig_e = u36!(0o606_202_333_123);
782 let orig_q = u18!(0o2777);
783 let orig_p = u18!(0o200);
784 let (target, xj, e, dismissed) = simulate_jmp(
785 &context,
786 u6!(1), orig_xj, orig_e, Address::from(orig_p), Address::from(orig_q), &SymbolicInstruction {
792 held: false,
793 configuration: u5!(0o22),
794 opcode: Opcode::Jmp,
795 index: u6!(1),
796 operand_address: OperandAddress::direct(target_base),
797 },
798 );
799 assert_eq!(target, Address::from(u18!(0o3302)));
801 assert_eq!(xj, orig_p.reinterpret_as_signed()); assert_eq!(e, orig_e); assert!(dismissed); }
805
806 #[test]
809 fn test_jmp_example_16() {
810 let context = make_ctx();
811 let target_base = Address::from(u18!(0o3302));
812 let orig_xj = Signed18Bit::from(0o20_i8);
813 let orig_e = u36!(0o606_202_333_123);
814 let orig_q = u18!(0o2777);
815 let orig_p = u18!(0o200);
816 let (target, xj, e, dismissed) = simulate_jmp(
817 &context,
818 u6!(1), orig_xj, orig_e, Address::from(orig_p), Address::from(orig_q), &SymbolicInstruction {
824 held: false,
825 configuration: u5!(0o23),
826 opcode: Opcode::Jmp,
827 index: u6!(1),
828 operand_address: OperandAddress::direct(target_base),
829 },
830 );
831 assert_eq!(target, Address::from(u18!(0o3322)));
833 assert_eq!(xj, orig_p.reinterpret_as_signed()); assert_eq!(e, orig_e); assert!(dismissed); }
837
838 fn simulate_sed(
840 ctx: &Context,
841 e: Unsigned36Bit, j: Unsigned6Bit,
843 xj: Signed18Bit, initial_tj: Unsigned36Bit, p: Address,
846 inst: &SymbolicInstruction,
847 ) -> Result<(Option<Alarm>, bool), String> {
848 const COMPLAIN: &str = "failed to set up SED test data";
849 let data_address: Address = match inst.operand_address.split() {
850 (true, _) => {
851 panic!("simulate_sed doesn't support deferred addressing yet")
852 }
853 (false, a) => a.index_by(xj),
854 };
855
856 let (mut control, mut mem) = setup(ctx, j, xj, e, p, Address::ZERO);
857 if let Err(e) = control.memory_store_without_exchange(
858 ctx,
859 &mut mem,
860 &data_address,
861 &initial_tj,
862 &UpdateE::No,
863 &MetaBitChange::None,
864 ) {
865 return Err(format!("failed to set up memory contents: {e}"));
866 }
867 control
868 .update_n_register(Instruction::from(inst).bits())
869 .expect(COMPLAIN);
870 let result = match control.op_sed(ctx, &mut mem) {
871 Err(e) => {
872 return Err(format!("Execution of SED instruction failed: {e}"));
873 }
874 Ok(result) => result,
875 };
876 if result.output.is_some() {
877 return Err("SED instruction should not generate output".to_string());
878 }
879 if result.poll_order_change.is_some() {
880 return Err("SED instruction should not change sequence flags".to_string());
881 }
882
883 if mem.get_e_register() != e {
885 return Err(format!(
886 "SED instruction incorrectly changed register E from {:o} to {:o}",
887 e,
888 mem.get_e_register()
889 ));
890 }
891 match result.program_counter_change {
892 Some(ProgramCounterChange::CounterUpdate) => Ok((None, true)), None => Ok((None, false)), Some(ProgramCounterChange::Jump(_)) => Err(format!(
895 "SED instruction performed an unexpected jump {:?}",
896 &result.program_counter_change
897 )),
898 Some(ProgramCounterChange::SequenceChange(_)) => {
899 Err("SED instruction should not change sequence flags".to_string())
900 }
901 Some(ProgramCounterChange::DismissAndWait(_)) => Err(
902 "SED instruction should not cause the current sequence's flag to drop".to_string(),
903 ),
904 Some(ProgramCounterChange::Stop(addr)) => Err(format!(
905 "SED instruction execution stopped at address {addr:?}",
906 )),
907 }
908 }
909
910 fn simulate_sed_no_alarm(
911 ctx: &Context,
912 e: Unsigned36Bit, j: Unsigned6Bit,
914 xj: Signed18Bit, initial_tj: Unsigned36Bit, p: Address,
917 inst: &SymbolicInstruction,
918 ) -> bool {
919 match simulate_sed(ctx, e, j, xj, initial_tj, p, inst) {
920 Err(err) => {
921 panic!("{}", err);
922 }
923 Ok((Some(alarm), _)) => {
924 panic!("SED instruction unexpectedly raised an alarm {alarm}");
925 }
926 Ok((None, skip)) => skip,
927 }
928 }
929
930 #[test]
933 fn test_sed_example_1_direct_skip() {
934 const INITIAL_E_REG_VALUE: Unsigned36Bit = u36!(0o444_444_444_444); let context = make_ctx();
936 let j = u6!(0);
937 let skipped = simulate_sed_no_alarm(
938 &context,
939 INITIAL_E_REG_VALUE,
940 j,
941 Signed18Bit::ZERO, u36!(0o555_555_555_555), Address::from(u18!(0o100)), &SymbolicInstruction {
945 held: false,
946 configuration: Unsigned5Bit::ZERO,
947 opcode: Opcode::Sed,
948 index: j,
949 operand_address: OperandAddress::direct(Address::from(u18!(0o100))),
950 },
951 );
952 assert!(
953 skipped,
954 "SED instruction failed to skip when it should have"
955 );
956 }
957
958 #[test]
961 fn test_sed_example_1_direct_noskip() {
962 const INITIAL_E_REG_VALUE: Unsigned36Bit = u36!(0o444_444_444_444); let context = make_ctx();
964 let j = u6!(0);
965 let skipped = simulate_sed_no_alarm(
966 &context,
967 INITIAL_E_REG_VALUE,
968 j,
969 Signed18Bit::ZERO, INITIAL_E_REG_VALUE, Address::from(u18!(0o100)), &SymbolicInstruction {
973 held: false,
974 configuration: Unsigned5Bit::ZERO,
975 opcode: Opcode::Sed,
976 index: j,
977 operand_address: OperandAddress::direct(Address::from(u18!(0o100))),
978 },
979 );
980 assert!(!skipped, "SED instruction skipped when it should not have");
981 }
982
983 #[test]
986 fn test_sed_example_2_direct_skip() {
987 const INITIAL_E_REG_VALUE: Unsigned36Bit = u36!(0o555_555_444_444); let context = make_ctx();
989 let j = u6!(0);
990 let skipped = simulate_sed_no_alarm(
991 &context,
992 INITIAL_E_REG_VALUE,
996 j,
997 Signed18Bit::ZERO, INITIAL_E_REG_VALUE, Address::from(u18!(0o100)), &SymbolicInstruction {
1001 held: false,
1002 configuration: u5!(2),
1003 opcode: Opcode::Sed,
1004 index: j,
1005 operand_address: OperandAddress::direct(Address::from(u18!(0o100))),
1006 },
1007 );
1008 assert!(skipped, "SED instruction should have skipped");
1010 }
1011
1012 #[test]
1016 fn test_sed_example_2_direct_noskip() {
1017 const INITIAL_E_REG_VALUE: Unsigned36Bit = u36!(0o070_070_333_333); let context = make_ctx();
1019 let j = u6!(0);
1020 let skipped = simulate_sed_no_alarm(
1021 &context,
1022 INITIAL_E_REG_VALUE,
1025 j,
1026 Signed18Bit::ZERO, u36!(0o333_333_020_020), Address::from(u18!(0o100)), &SymbolicInstruction {
1030 held: false,
1031 configuration: u5!(2),
1032 opcode: Opcode::Sed,
1033 index: j,
1034 operand_address: OperandAddress::direct(Address::from(u18!(0o100))),
1035 },
1036 );
1037 assert!(!skipped, "SED instruction should not have skipped");
1040 }
1041}