1use tracing::{Level, event};
15
16use super::alarm::Alarm;
17use super::context::Context;
18use super::control::{ControlUnit, MemoryUnit, OpcodeResult, UpdateE};
19use super::exchanger::exchanged_value_for_load;
20use base::prelude::*;
21
22impl ControlUnit {
23 pub(crate) fn op_lda(
26 &mut self,
27 ctx: &Context,
28 mem: &mut MemoryUnit,
29 ) -> Result<OpcodeResult, Alarm> {
30 let new_value = self.op_load_value(ctx, &mem.get_a_register(), mem, &UpdateE::Yes)?;
31 mem.set_a_register(new_value);
32 Ok(OpcodeResult::default())
33 }
34
35 pub(crate) fn op_ldb(
38 &mut self,
39 ctx: &Context,
40 mem: &mut MemoryUnit,
41 ) -> Result<OpcodeResult, Alarm> {
42 let new_value = self.op_load_value(ctx, &mem.get_b_register(), mem, &UpdateE::Yes)?;
43 mem.set_b_register(new_value);
44 Ok(OpcodeResult::default())
45 }
46
47 pub(crate) fn op_ldc(
50 &mut self,
51 ctx: &Context,
52 mem: &mut MemoryUnit,
53 ) -> Result<OpcodeResult, Alarm> {
54 let new_value = self.op_load_value(ctx, &mem.get_c_register(), mem, &UpdateE::Yes)?;
55 mem.set_c_register(new_value);
56 Ok(OpcodeResult::default())
57 }
58
59 pub(crate) fn op_ldd(
62 &mut self,
63 ctx: &Context,
64 mem: &mut MemoryUnit,
65 ) -> Result<OpcodeResult, Alarm> {
66 let new_value = self.op_load_value(ctx, &mem.get_d_register(), mem, &UpdateE::Yes)?;
67 mem.set_d_register(new_value);
68 Ok(OpcodeResult::default())
69 }
70
71 pub(crate) fn op_lde(
74 &mut self,
75 ctx: &Context,
76 mem: &mut MemoryUnit,
77 ) -> Result<OpcodeResult, Alarm> {
78 let old_value = mem.get_e_register();
83 let new_value = self.op_load_value(ctx, &old_value, mem, &UpdateE::No)?;
84 mem.set_e_register(new_value);
85 Ok(OpcodeResult::default())
86 }
87
88 pub(crate) fn op_sta(
91 &mut self,
92 ctx: &Context,
93 mem: &mut MemoryUnit,
94 ) -> Result<OpcodeResult, Alarm> {
95 self.op_store_ae_register(ctx, mem.get_a_register(), mem, &UpdateE::Yes)
96 }
97
98 pub(crate) fn op_stb(
101 &mut self,
102 ctx: &Context,
103 mem: &mut MemoryUnit,
104 ) -> Result<OpcodeResult, Alarm> {
105 self.op_store_ae_register(ctx, mem.get_b_register(), mem, &UpdateE::Yes)
106 }
107
108 pub(crate) fn op_stc(
111 &mut self,
112 ctx: &Context,
113 mem: &mut MemoryUnit,
114 ) -> Result<OpcodeResult, Alarm> {
115 self.op_store_ae_register(ctx, mem.get_c_register(), mem, &UpdateE::Yes)
116 }
117
118 pub(crate) fn op_std(
121 &mut self,
122 ctx: &Context,
123 mem: &mut MemoryUnit,
124 ) -> Result<OpcodeResult, Alarm> {
125 self.op_store_ae_register(ctx, mem.get_d_register(), mem, &UpdateE::Yes)
126 }
127
128 pub(crate) fn op_ste(
131 &mut self,
132 ctx: &Context,
133 mem: &mut MemoryUnit,
134 ) -> Result<OpcodeResult, Alarm> {
135 self.op_store_ae_register(ctx, mem.get_e_register(), mem, &UpdateE::No)
139 }
140
141 fn op_store_ae_register(
143 &mut self,
144 ctx: &Context,
145 register_value: Unsigned36Bit,
146 mem: &mut MemoryUnit,
147 update_e: &UpdateE,
148 ) -> Result<OpcodeResult, Alarm> {
149 let target: Address = self.operand_address_with_optional_defer_and_index(ctx, mem)?;
150 event!(
151 Level::TRACE,
152 "storing register value {register_value:o} at {target:o}"
153 );
154 self.memory_read_and_update_with_exchange(ctx, mem, &target, update_e, |_| register_value)
155 .map(|()| OpcodeResult::default())
156 }
157
158 fn op_load_value(
160 &mut self,
161 ctx: &Context,
162 existing: &Unsigned36Bit,
163 mem: &mut MemoryUnit,
164 update_e: &UpdateE,
165 ) -> Result<Unsigned36Bit, Alarm> {
166 let target: Address = self.operand_address_with_optional_defer_and_index(ctx, mem)?;
167 let (memword, _extra) =
168 self.fetch_operand_from_address_without_exchange(ctx, mem, &target, update_e)?;
169 let exchanged = exchanged_value_for_load(&self.get_config(), &memword, existing);
170 Ok(exchanged)
171 }
172}
173
174#[cfg(test)]
175mod tests {
176 use super::super::super::context::Context;
177 use super::super::super::control::ConfigurationMemorySetup;
178 use super::super::super::exchanger::SystemConfiguration;
179 use super::super::super::memory::{MemoryMapped, MetaBitChange};
180 use super::super::super::{MemoryConfiguration, MemoryUnit};
181 use super::super::{ControlUnit, PanicOnUnmaskedAlarm, UpdateE};
182 use base::prelude::*;
183 use base::subword::right_half;
184 use core::time::Duration;
185
186 #[derive(Debug)]
187 enum ArithmeticUnitRegister {
188 A,
190 B,
191 C,
192 D,
193 E,
196 }
197
198 fn make_ctx() -> Context {
199 Context {
200 simulated_time: Duration::new(42, 42),
201 real_elapsed_time: Duration::new(7, 12),
202 }
203 }
204
205 fn get_register_value(mem: &MemoryUnit, which: ArithmeticUnitRegister) -> Unsigned36Bit {
206 use ArithmeticUnitRegister::*;
207 match which {
208 A => mem.get_a_register(),
209 B => mem.get_b_register(),
210 C => mem.get_c_register(),
211 D => mem.get_d_register(),
212 E => mem.get_e_register(),
213 }
214 }
215
216 fn set_up_load(
217 ctx: &Context,
218 a: Unsigned36Bit,
219 b: Unsigned36Bit,
220 c: Unsigned36Bit,
221 d: Unsigned36Bit,
222 e: Unsigned36Bit,
223 ) -> (ControlUnit, MemoryUnit) {
224 let control = ControlUnit::new(
225 PanicOnUnmaskedAlarm::Yes,
226 ConfigurationMemorySetup::StandardForTestingOnly,
227 );
228 let mut mem = MemoryUnit::new(
229 ctx,
230 &MemoryConfiguration {
231 with_u_memory: false,
232 },
233 );
234 mem.set_a_register(a);
235 mem.set_b_register(b);
236 mem.set_c_register(c);
237 mem.set_d_register(d);
238 mem.set_e_register(e);
239 (control, mem)
240 }
241
242 #[allow(clippy::too_many_arguments)]
244 fn simulate_load(
245 ctx: &Context,
246 final_operand_address: Unsigned18Bit,
247 target_register: ArithmeticUnitRegister,
248 configuration: SystemConfiguration,
249 mem_word: Option<Unsigned36Bit>,
250 a: Unsigned36Bit,
251 b: Unsigned36Bit,
252 c: Unsigned36Bit,
253 d: Unsigned36Bit,
254 e: Unsigned36Bit,
255 j: Unsigned6Bit,
256 xj: Signed18Bit,
257 defer_index: Option<Signed18Bit>,
258 ) -> (Unsigned36Bit, Unsigned36Bit) {
259 let (mut control, mut mem) = set_up_load(ctx, a, b, c, d, e);
260 if let Some(w) = mem_word {
261 control
263 .memory_store_without_exchange(
264 ctx,
265 &mut mem,
266 &Address::from(final_operand_address),
267 &w,
268 &UpdateE::No,
269 &MetaBitChange::None,
270 )
271 .expect("simulate_load should be able to set up the final operand");
272 }
273
274 let base: Signed18Bit = final_operand_address
287 .reinterpret_as_signed()
288 .checked_sub(defer_index.unwrap_or(Signed18Bit::ZERO))
289 .and_then(|x| x.checked_sub(xj))
290 .expect("test data caused arithmetic overflow");
291 let defer: Unsigned36Bit = join_halves(
292 defer_index.unwrap_or_default().reinterpret_as_unsigned(),
293 base.reinterpret_as_unsigned(),
294 );
295 control
296 .memory_store_without_exchange(
297 ctx,
298 &mut mem,
299 &Address::from(u18!(0o200)),
300 &defer,
301 &UpdateE::No,
302 &MetaBitChange::None,
303 )
304 .expect("simulate_load should be able to write to address 0o100");
305
306 control.regs.f_memory[1] = configuration;
307
308 let opcode = match target_register {
309 ArithmeticUnitRegister::A => Opcode::Lda,
310 ArithmeticUnitRegister::B => Opcode::Ldb,
311 ArithmeticUnitRegister::C => Opcode::Ldc,
312 ArithmeticUnitRegister::D => Opcode::Ldd,
313 ArithmeticUnitRegister::E => Opcode::Lde,
314 };
315 let inst = SymbolicInstruction {
316 held: false,
317 configuration: Unsigned5Bit::ONE,
318 opcode,
319 index: j,
320 operand_address: if defer_index.is_some() {
321 OperandAddress::deferred(Address::from(u18!(0o200)))
322 } else {
323 OperandAddress::direct(Address::from(final_operand_address))
324 },
325 };
326 control
327 .update_n_register(Instruction::from(&inst).bits())
328 .expect("should be able to set N register");
329
330 let result = match target_register {
331 ArithmeticUnitRegister::A => control.op_lda(ctx, &mut mem),
332 ArithmeticUnitRegister::B => control.op_ldb(ctx, &mut mem),
333 ArithmeticUnitRegister::C => control.op_ldc(ctx, &mut mem),
334 ArithmeticUnitRegister::D => control.op_ldd(ctx, &mut mem),
335 ArithmeticUnitRegister::E => control.op_lde(ctx, &mut mem),
336 };
337 if let Err(e) = result {
338 panic!("{opcode:?} instruction failed: {e}");
339 }
340 (
341 get_register_value(&mem, target_register),
342 mem.get_e_register(),
343 )
344 }
345
346 fn set_up_store<F>(
347 ctx: &Context,
348 mem_word: Unsigned36Bit,
349 working_address: &Address,
350 mut mem_init: F,
351 ) -> (ControlUnit, MemoryUnit)
352 where
353 F: FnMut(&mut MemoryUnit),
354 {
355 const COMPLAIN: &str = "failed to set up load/store test data";
356 let mut control = ControlUnit::new(
357 PanicOnUnmaskedAlarm::Yes,
358 ConfigurationMemorySetup::StandardForTestingOnly,
359 );
360 let mut mem = MemoryUnit::new(
361 ctx,
362 &MemoryConfiguration {
363 with_u_memory: false,
364 },
365 );
366 control
367 .memory_store_without_exchange(
368 ctx,
369 &mut mem,
370 working_address,
371 &mem_word,
372 &UpdateE::No,
373 &MetaBitChange::None,
374 )
375 .expect(COMPLAIN);
376 mem_init(&mut mem);
377 (control, mem)
378 }
379
380 #[allow(clippy::too_many_arguments)]
381 fn simulate_store(
382 ctx: &Context,
383 control: &mut ControlUnit,
384 mem: &mut MemoryUnit,
385 working_address: &Address,
386 j: Unsigned6Bit,
387 opcode: Opcode,
388 defer: bool,
389 configuration: SystemConfiguration,
390 ) -> (Unsigned36Bit, Unsigned36Bit) {
391 let complain = format!("failed to execute store instruction {opcode:?}");
392 control.regs.f_memory[1] = configuration;
393 let inst = SymbolicInstruction {
394 held: false,
395 configuration: Unsigned5Bit::ONE,
396 opcode,
397 index: j,
398 operand_address: if defer {
399 todo!("defer is not yet implemented");
400 } else {
401 OperandAddress::direct(*working_address)
402 },
403 };
404 control
405 .update_n_register(Instruction::from(&inst).bits())
406 .expect(&complain);
407 let f = match opcode {
408 Opcode::Ste => ControlUnit::op_ste,
409 _ => {
410 panic!("opcode {opcode:?} is not yet supported");
411 }
412 };
413 if let Err(e) = f(control, ctx, mem) {
414 panic!("{opcode:?} instruction failed: {e}");
415 }
416 match mem.fetch(ctx, working_address, &MetaBitChange::None) {
417 Ok((stored, _)) => (stored, mem.get_e_register()),
418 Err(e) => {
419 panic!("unable to retrieve the stored word: {e}");
420 }
421 }
422 }
423
424 #[test]
426 fn test_lde_example_1() {
427 let context = make_ctx();
428 let input = u36!(0o444_333_222_111);
429 let (output, e) = simulate_load(
430 &context,
431 u18!(0o10000),
432 ArithmeticUnitRegister::E,
433 SystemConfiguration::zero(),
434 Some(input),
435 u36!(1), u36!(2), u36!(3), u36!(4), u36!(5), u6!(1), u18!(0o4).reinterpret_as_signed(), None, );
444 assert_eq!(output, input);
445 assert_eq!(e, input);
446 }
447
448 #[test]
451 fn test_lde_example_2() {
452 let context = make_ctx();
453 let input = u36!(0o404_303_202_101);
454 let orig_e = u36!(0o545_535_525_515);
455 let (new_e, e) = simulate_load(
456 &context,
457 u18!(0o10000),
458 ArithmeticUnitRegister::E,
459 SystemConfiguration::from(u9!(0o340)), Some(input),
461 u36!(0o141_131_121_111), u36!(0o242_232_222_212), u36!(0o343_333_323_313), u36!(0o444_434_424_414), orig_e, u6!(1), u18!(0o4).reinterpret_as_signed(), None, );
470 assert_eq!(new_e, u36!(0o545_535_202_101));
472 assert_eq!(e, new_e);
473 }
474
475 #[test]
478 fn test_lda_example_2() {
479 let context = make_ctx();
480 let input = u36!(0o404_303_202_101);
481 let orig_e = u36!(0o545_535_525_515);
482 let (new_a, e) = simulate_load(
483 &context,
484 u18!(0o10000),
485 ArithmeticUnitRegister::A,
486 SystemConfiguration::from(u9!(0o340)), Some(input),
488 u36!(0o141_131_121_111), u36!(0o242_232_222_212), u36!(0o343_333_323_313), u36!(0o444_434_424_414), orig_e, u6!(1), u18!(0o4).reinterpret_as_signed(), None, );
497 assert_eq!(new_a, u36!(0o141_131_202_101));
500 assert_eq!(e, input);
501 }
502
503 #[test]
506 fn test_ldc_example_3() {
507 let context = make_ctx();
508 let input = u36!(0o404_303_402_101);
510 let orig_e = u36!(0o545_535_525_515);
511 let (new_c, e) = simulate_load(
512 &context,
513 u18!(0o10000),
514 ArithmeticUnitRegister::C,
515 SystemConfiguration::from(u9!(0o140)), Some(input),
517 u36!(0o141_131_121_111), u36!(0o242_232_222_212), u36!(0o343_333_323_313), u36!(0o444_434_424_414), orig_e, u6!(1), u18!(0o4).reinterpret_as_signed(), None, );
526 assert_eq!(new_c, u36!(0o777_777_402_101));
530 assert_eq!(e, input);
531 }
532
533 #[test]
536 fn test_ldd_example_4() {
537 let context = make_ctx();
538 let input = u36!(0o404_303_202_101);
539 let orig_e = u36!(0o545_535_525_515);
540 let orig_d = u36!(0o444_434_424_414);
541 let (new_d, new_e) = simulate_load(
542 &context,
543 u18!(0o10000),
544 ArithmeticUnitRegister::D,
545 SystemConfiguration::from(u9!(0o342)), Some(input),
547 u36!(0o141_131_121_111), u36!(0o242_232_222_212), u36!(0o343_333_323_313), orig_d, orig_e, u6!(1), u18!(0o4).reinterpret_as_signed(), None, );
556 assert_eq!(new_d, u36!(0o444_434_404_303)); assert_eq!(new_e, input); }
559
560 #[test]
566 fn test_ldb_example_5() {
567 let context = make_ctx();
568 let b_register_address: Unsigned18Bit = u18!(0o0377605);
570 let orig_b = u36!(0o242_232_222_212);
571 let (new_b, new_e) = simulate_load(
572 &context,
573 b_register_address,
574 ArithmeticUnitRegister::B,
575 SystemConfiguration::from(u9!(0o342)), None,
577 u36!(0o141_131_121_111), orig_b, u36!(0o343_333_323_313), u36!(0o444_434_424_414), u36!(0o545_535_525_515), u6!(1), u18!(0o4).reinterpret_as_signed(), None, );
586 assert_eq!(new_b, u36!(0o242_232_242_232));
588 assert_eq!(new_e, orig_b); }
590
591 #[test]
594 fn test_ldd_example_6() {
595 let context = make_ctx();
596 let input = u36!(0o404_303_202_101);
598 let orig_e = u36!(0o545_535_525_515);
599 let orig_d = u36!(0o444_434_424_414);
600 let (new_d, new_e) = simulate_load(
601 &context,
602 u18!(0o10000),
603 ArithmeticUnitRegister::D,
604 SystemConfiguration::from(u9!(0o163)), Some(input),
606 u36!(0o141_131_121_111), u36!(0o242_232_222_212), u36!(0o343_333_323_313), orig_d, orig_e, u6!(1), u18!(0o4).reinterpret_as_signed(), None, );
615 assert_eq!(new_d, u36!(0o777_777_777_404), "new value for D is wrong");
619 assert_eq!(new_e, input, "new value for E is wrong"); }
621
622 #[test]
623 fn test_ste_example_1() {
624 let context = make_ctx();
625 let input = u36!(0o004_003_002_001);
626 let working_address: Address = Address::from(u18!(0o100));
627 let (mut control, mut mem) =
628 set_up_store(&context, u36!(0o444_333_222_111), &working_address, |mem| {
629 mem.set_e_register(input);
630 });
631 let (result, _e) = simulate_store(
634 &context,
635 &mut control,
636 &mut mem,
637 &working_address,
638 Unsigned6Bit::ZERO, Opcode::Ste,
640 false,
641 SystemConfiguration::from(Unsigned9Bit::ZERO),
642 );
643 assert_eq!(input, result);
644 }
645
646 #[test]
649 fn test_ste_example_3() {
650 let context = make_ctx();
651 let initial_value_at_100 = u36!(0o004_003_002_001);
652 let initial_e = u36!(0o444_333_222_111);
653 let working_address: Address = Address::from(u18!(0o100));
654 let (mut control, mut mem) =
655 set_up_store(&context, initial_value_at_100, &working_address, |mem| {
656 mem.set_e_register(initial_e);
657 });
658
659 let (result, e) = simulate_store(
665 &context,
666 &mut control,
667 &mut mem,
668 &working_address,
669 Unsigned6Bit::ZERO, Opcode::Ste,
671 false,
672 SystemConfiguration::from(u9!(0o342)),
674 );
675
676 assert_eq!(e, initial_e, "E register should be unchanged");
679 let expected = u36!(0o222_111_002_001);
682 let expected2 = join_halves(right_half(initial_e), right_half(initial_value_at_100));
683 assert_eq!(expected, expected2, "test is internally inconsistent");
684 assert_eq!(result, expected, "incorrect value stored at 0o100");
685 }
686}