cpu/control/
op_configuration.rs1use base::prelude::*;
9use base::subword;
10
11use super::Alarm;
12use super::context::Context;
13use super::control::{ControlUnit, OpcodeResult, UpdateE};
14use super::exchanger::SystemConfiguration;
15use super::memory::MemoryUnit;
16
17use tracing::{Level, event};
18
19impl ControlUnit {
20 pub(crate) fn op_spg(
22 &mut self,
23 ctx: &Context,
24 mem: &mut MemoryUnit,
25 ) -> Result<OpcodeResult, Alarm> {
26 let c = usize::from(self.regs.n.configuration());
27 let target = self.operand_address_with_optional_defer_and_index(ctx, mem)?;
28 let (word, _meta) =
29 self.fetch_operand_from_address_without_exchange(ctx, mem, &target, &UpdateE::Yes)?;
30 for (quarter_number, cfg_value) in subword::quarters(word).iter().rev().enumerate() {
31 let pos = c + quarter_number;
32 let newvalue = (*cfg_value).into();
33 if pos != 0 {
34 self.regs.f_memory[pos] = newvalue;
35 } else if newvalue != SystemConfiguration::zero() {
36 event!(
37 Level::WARN,
38 "Ignoring attempt to set system configuration 0 to {:?}",
39 newvalue
40 );
41 }
42 }
43 Ok(OpcodeResult::default())
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use super::super::super::context::Context;
50 use super::super::super::control::{ConfigurationMemorySetup, PanicOnUnmaskedAlarm, UpdateE};
51 use super::super::super::exchanger::SystemConfiguration;
52 use super::super::super::memory::MetaBitChange;
53 use super::super::super::{MemoryConfiguration, MemoryUnit};
54 use base::instruction::{Opcode, SymbolicInstruction};
55 use base::prelude::*;
56 use core::time::Duration;
57
58 use super::ControlUnit;
59
60 fn make_ctx() -> Context {
61 Context {
62 simulated_time: Duration::new(42, 42),
63 real_elapsed_time: Duration::new(7, 12),
64 }
65 }
66
67 fn cfg_loc(n: u8) -> Unsigned5Bit {
68 Unsigned5Bit::try_from(n).expect("bad test data; config location out of range")
69 }
70
71 fn cfg_val(n: u16) -> SystemConfiguration {
72 SystemConfiguration::from(Unsigned9Bit::try_from(n).expect("bad system config number"))
73 }
74
75 fn simulate_spg(
78 ctx: &Context,
79 cfg: u8,
80 configdata: Unsigned36Bit,
81 ) -> ([SystemConfiguration; 4], Unsigned36Bit) {
82 const COMPLAIN: &str = "failed to set up test data";
83
84 let mut control = ControlUnit::new(
86 PanicOnUnmaskedAlarm::Yes,
87 ConfigurationMemorySetup::Uninitialised,
88 );
89 let mut mem = MemoryUnit::new(
90 ctx,
91 &MemoryConfiguration {
92 with_u_memory: false,
93 },
94 );
95 let configdata_address = Address::from(u18!(0o100));
96 control
97 .memory_store_without_exchange(
98 ctx,
99 &mut mem,
100 &configdata_address,
101 &configdata,
102 &UpdateE::Yes,
103 &MetaBitChange::None,
104 )
105 .expect(COMPLAIN);
106
107 let inst = SymbolicInstruction {
110 held: false,
111 configuration: Unsigned5Bit::try_from(cfg).expect(COMPLAIN),
112 opcode: Opcode::Spg,
113 index: Unsigned6Bit::ZERO,
114 operand_address: OperandAddress::direct(configdata_address),
115 };
116 control
117 .update_n_register(Instruction::from(&inst).bits())
118 .expect(COMPLAIN);
119 if let Err(e) = control.op_spg(ctx, &mut mem) {
120 panic!("SPG instruction failed: {e}");
121 }
122
123 (
124 [
125 control.regs.get_f_mem(cfg_loc(cfg)),
126 control.regs.get_f_mem(cfg_loc(cfg + 1)),
127 control.regs.get_f_mem(cfg_loc(cfg + 2)),
128 control.regs.get_f_mem(cfg_loc(cfg + 3)),
129 ],
130 mem.get_e_register(),
131 )
132 }
133
134 #[test]
137 fn op_spg_ordering() {
138 let word = u36!(0o_410763_762761);
142 let ctx = make_ctx();
143 let (values, e) = simulate_spg(&ctx, 4, word);
144
145 assert_eq!(values[0], cfg_val(0o761));
148 assert_eq!(values[1], cfg_val(0o762));
150 assert_eq!(values[2], cfg_val(0o763));
152 assert_eq!(values[3], cfg_val(0o410));
154
155 assert_eq!(e, word, "E register was unaffected");
156 }
157
158 #[test]
163 fn op_spg_zero_invariant() {
164 let word = u36!(0o_410763_762761);
168 let context = make_ctx();
169 let (values, e) = simulate_spg(&context, 0, word);
170
171 assert_eq!(values[0], cfg_val(0o0));
174 assert_eq!(values[1], cfg_val(0o762));
176 assert_eq!(values[2], cfg_val(0o763));
178 assert_eq!(values[3], cfg_val(0o410));
180
181 assert_eq!(e, word, "E register was unaffected");
183 }
184}