1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
use awint::{awint_dag::triple_arena::OrdArena, Awi};
use crate::{
ensemble::{Ensemble, PBack, PExternal},
epoch::get_current_epoch,
route::{EdgeKind, EmbeddingKind, PConfig, Programmability, Router},
Error, LazyAwi,
};
#[derive(Debug, Clone)]
pub struct Config {
/// stable `Ptr` for the target
pub p_external: PExternal,
/// The index in the `RNode`
pub bit_i: usize,
/// The bit value the configuration wants. `None` is for not yet determined
/// or for if the value can be set to `Value::Unknown`.
pub value: Option<bool>,
}
/// The channeler for the target needs to know which bits the router can use to
/// configure different behaviors.
#[derive(Debug, Clone)]
pub struct Configurator {
// `ThisEquiv` `PBack` to `PExternal` mapping for bits we are allowed to configure
pub configurations: OrdArena<PConfig, PBack, Config>,
}
impl Configurator {
pub fn new() -> Self {
Self {
configurations: OrdArena::new(),
}
}
pub fn find(&self, p_equiv: PBack) -> Option<PConfig> {
self.configurations.find_key(&p_equiv)
}
/// Tell the router what bits it can use for programming the target. Uses
/// the currently active `Epoch`.
pub fn configurable<L: std::borrow::Borrow<LazyAwi>>(
&mut self,
config: &L,
) -> Result<(), Error> {
let epoch_shared = get_current_epoch()?;
let lock = epoch_shared.epoch_data.borrow();
let ensemble = &lock.ensemble;
self.ensemble_make_configurable(ensemble, config)
}
/// Tell the router what bits it can use for programming the target
pub fn ensemble_make_configurable<L: std::borrow::Borrow<LazyAwi>>(
&mut self,
ensemble: &Ensemble,
config: &L,
) -> Result<(), Error> {
let config = config.borrow();
let p_external = config.p_external();
let (_, rnode) = ensemble.notary.get_rnode(p_external)?;
if let Some(bits) = rnode.bits() {
for (bit_i, bit) in bits.iter().copied().enumerate() {
if let Some(bit) = bit {
let p_equiv = ensemble.backrefs.get_val(bit).unwrap().p_self_equiv;
let (_, replaced) = self.configurations.insert(p_equiv, Config {
p_external,
bit_i,
value: None,
});
// we may want to allow this, if we have a mechanism to make sure they are
// set to the same thing
if replaced.is_some() {
return Err(Error::OtherString(format!(
"`configurable({config:#?})`: found that the same bit as a previous \
one is configurable, this may be because `configurable` was called \
twice on the same or equivalent bit"
)));
}
}
}
} else {
return Err(Error::OtherStr(
"`configurable({config:#?})`: found that the epoch has not been lowered and \
preferably optimized",
));
}
Ok(())
}
}
impl Router {
/// Requires that the target epoch be resumed and is the active epoch
pub fn config_target(&self) -> Result<(), Error> {
todo!()
}
/*pub fn ensemble_config_target(&self, ensemble: &mut Ensemble) -> Result<(), Error> {
Ok(())
}*/
/// Sets all the configurations derived from final embeddings
pub(crate) fn set_configurations(&mut self) -> Result<(), Error> {
// assumes that all config `value`s are set to `None` and we only route once,
// otherwise we have to set them all to `None` at the start because it is used
// to detect if there are contradictions
for embedding in self.embeddings.vals() {
match embedding.program {
EmbeddingKind::Node(_) => {
// follow the `SelectorLut`s of the hyperpath
for path in embedding.target_hyperpath.paths() {
for edge in path.edges() {
match edge.kind {
EdgeKind::Transverse(q_cedge, source_i) => {
let cedge = self.target_channeler.cedges.get(q_cedge).unwrap();
match cedge.programmability() {
// no-op with respect to configuration
Programmability::TNode => (),
// there are identity like cases where we might want to
// traverse these kinds
Programmability::StaticLut(_) => todo!(),
Programmability::ArbitraryLut(_) => todo!(),
Programmability::SelectorLut(selector_lut) => {
let inx_config = selector_lut.inx_config();
assert!(source_i < (1 << inx_config.len()));
let i = Awi::from_usize(source_i);
for (inx_i, p_config) in
inx_config.iter().copied().enumerate()
{
let value = &mut self
.configurator
.configurations
.get_val_mut(p_config)
.unwrap()
.value;
let desired_value = Some(i.get(inx_i).unwrap());
if value.is_some() && (*value != desired_value) {
// means hyperpaths or base embeddings are
// conflicting
panic!(
"bug in router, a configuration bit has \
already been set and contradicts another \
desired configuration"
);
}
*value = desired_value;
}
}
// the hyperpath should be fully lowered
Programmability::Bulk(_) => unreachable!(),
}
}
// the hyperpath should be fully lowered into base level traversals
EdgeKind::Concentrate | EdgeKind::Dilute => unreachable!(),
}
}
}
}
// need lowering to and configuration setting of `ArbitraryLut`s
EmbeddingKind::Edge(_) => todo!(),
}
}
Ok(())
}
}
impl Default for Configurator {
fn default() -> Self {
Self::new()
}
}