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
//! The runtime's host, which acts as a translation layer between the AST and
//! the runtime.
use crate::prelude::*;
use crate::{
ast::{Book, Net, Tree},
run::{self, Addr, Def, Instruction, InterpretedDef, LabSet, Mode, Port, Tag, TrgId, Wire},
stdlib::HostedDef,
util::create_var,
};
use core::ops::{Deref, DerefMut, RangeFrom};
mod calc_labels;
mod encode;
mod readback;
use calc_labels::calculate_label_sets;
/// Stores a bidirectional mapping between names and runtime defs.
#[derive(Default)]
pub struct Host {
/// the forward mapping, from a name to the runtime def
pub defs: Map<String, DefRef>,
/// the backward mapping, from the address of a runtime def to the name
pub back: Map<Addr, String>,
}
/// A potentially-owned reference to a [`Def`]. Vitally, the address of the
/// `Def` is stable, even if the `DefRef` moves -- this is why
/// [`std::Borrow::Cow`] cannot be used here.
pub enum DefRef {
Owned(Box<dyn DerefMut<Target = Def> + Send + Sync>),
Static(&'static Def),
}
impl Deref for DefRef {
type Target = Def;
fn deref(&self) -> &Def {
match self {
DefRef::Owned(x) => x,
DefRef::Static(x) => x,
}
}
}
impl Host {
pub fn new(book: &Book) -> Host {
let mut host = Host::default();
host.insert_book(book);
host
}
/// Converts all of the nets from the book into runtime defs, and inserts them
/// into the host. The book must not have refs that are not in the book or the
/// host.
pub fn insert_book(&mut self, book: &Book) {
self.insert_book_with_default(book, &mut |x| panic!("Found reference {x:?}, which is not in the book!"))
}
/// Like `insert_book`, but allows specifying a function (`default_def`) that
/// will be run when the name of a definition is not found in the book.
/// The return value of the function will be inserted into the host.
pub fn insert_book_with_default(&mut self, book: &Book, default_def: &mut dyn FnMut(&str) -> DefRef) {
#[cfg(feature = "std")]
{
self.defs.reserve(book.len());
self.back.reserve(book.len());
}
// Because there may be circular dependencies, inserting the definitions
// must be done in two phases:
// First, we insert empty defs into the host. Even though their instructions
// are not yet set, the address of the def will not change, meaning that
// `net_to_runtime_def` can safely use `Port::new_def` on them.
for (name, labs) in calculate_label_sets(book, |nam| match self.defs.get(nam) {
Some(x) => x.labs.clone(),
None => {
self.insert_def(nam, default_def(nam));
self.defs[nam].labs.clone()
}
})
.into_iter()
{
let def = unsafe { HostedDef::new_hosted(labs, InterpretedDef::default()) };
self.insert_def(name, def);
}
// Now that `defs` is fully populated, we can fill in the instructions of
// each of the new defs.
for (nam, net) in book.iter() {
let data = self.encode_def(net);
self.get_mut::<HostedDef<InterpretedDef>>(nam).data.0 = data;
}
}
/// Inserts a singular def into the mapping.
pub fn insert_def(&mut self, name: &str, def: DefRef) {
self.back.insert(Port::new_ref(&def).addr(), name.to_owned());
self.defs.insert(name.to_owned(), def);
}
/// Returns a mutable [`Def`] named `name`.
pub fn get_mut<T: Send + Sync + 'static>(&mut self, name: &str) -> &mut Def<T> {
match self.defs.get_mut(name).unwrap() {
DefRef::Owned(def) => def.downcast_mut().unwrap(),
DefRef::Static(_) => unreachable!(),
}
}
}