prjunnamed_netlist/
target.rs

1use std::borrow::Cow;
2use std::fmt::{Debug, Display};
3use std::error::Error;
4use std::collections::BTreeMap;
5use std::ops::Range;
6use std::sync::{Arc, Mutex};
7
8use crate::{CellRef, Const, Design, Instance, IoValue, ParamValue, TargetCell, Trit, Value};
9
10pub trait Target: Debug {
11    /// Get target name. The name of the target can be used to construct a new instance of it.
12    fn name(&self) -> &str;
13
14    /// Get target options. Target options define the exact variant of the target, and include
15    /// the device family, device name, speed grade, temperature variant, and any other parameters
16    /// required to fully define a specific device.
17    fn options(&self) -> BTreeMap<String, String>;
18
19    /// Get prototypes of target cells. Prototypes in conjunction with the target cell itself define
20    /// the connectivity and properties of the primitive instance.
21    fn prototype(&self, name: &str) -> Option<&TargetPrototype>;
22
23    /// Validate target-specific constraints. Conformance with the prototype is always validated
24    /// by `Design::validate`.
25    fn validate(&self, design: &Design, cell: &TargetCell);
26
27    /// Convert generic instances into target cells.
28    fn import(&self, design: &mut Design) -> Result<(), TargetImportError>;
29
30    /// Convert target cells into generic instances.
31    fn export(&self, design: &mut Design);
32
33    /// Run the complete synthesis flow.
34    fn synthesize(&self, design: &mut Design) -> Result<(), ()>;
35}
36
37#[derive(Debug, Clone, PartialEq, Eq)]
38pub enum TargetParamKind {
39    Bits(usize),
40    Bool,
41    IntEnum(Vec<i64>),
42    StringEnum(Vec<String>),
43}
44
45impl TargetParamKind {
46    pub fn is_valid(&self, value: &ParamValue) -> bool {
47        match (self, value) {
48            (TargetParamKind::Bits(width), ParamValue::Const(value)) => value.len() == *width,
49            (TargetParamKind::Bool, ParamValue::Const(value)) => value.len() == 1 && !value.has_undef(),
50            (TargetParamKind::IntEnum(items), ParamValue::Int(value)) => items.contains(value),
51            (TargetParamKind::StringEnum(items), ParamValue::String(value)) => items.contains(value),
52            _ => false,
53        }
54    }
55
56    pub fn cast(&self, value: &ParamValue) -> Option<ParamValue> {
57        match (self, value) {
58            (TargetParamKind::Bits(width), ParamValue::Const(value)) if value.len() == *width => {
59                Some(ParamValue::Const(value.clone()))
60            }
61            (TargetParamKind::Bits(width), ParamValue::Int(value)) if *value >= 0 && *value < 1 << *width => {
62                Some(ParamValue::Const(Const::from_uint((*value).try_into().unwrap(), *width)))
63            }
64            (TargetParamKind::Bool, ParamValue::Int(value)) => match *value {
65                1 => Some(ParamValue::Const(Const::ones(1))),
66                0 => Some(ParamValue::Const(Const::zero(1))),
67                _ => None,
68            },
69            (TargetParamKind::Bool, ParamValue::Const(value)) => match value.try_into() {
70                Ok(0u64) => Some(ParamValue::Const(Const::zero(1))),
71                Ok(1u64) => Some(ParamValue::Const(Const::ones(1))),
72                _ => None,
73            },
74            (TargetParamKind::IntEnum(items), ParamValue::Const(value)) => {
75                let value = value.try_into().ok()?;
76                if items.contains(&value) {
77                    Some(ParamValue::Int(value))
78                } else {
79                    None
80                }
81            }
82            (TargetParamKind::IntEnum(items), ParamValue::Int(value)) if items.contains(value) => {
83                Some(ParamValue::Int(*value))
84            }
85            (TargetParamKind::StringEnum(items), ParamValue::String(value)) if items.contains(value) => {
86                Some(ParamValue::String(value.clone()))
87            }
88            _ => None,
89        }
90    }
91}
92
93#[derive(Debug, Clone, PartialEq, Eq)]
94pub struct TargetParam {
95    pub name: String,
96    pub kind: TargetParamKind,
97    pub default: ParamValue,
98    pub index: usize,
99}
100
101#[derive(Debug, Clone, PartialEq, Eq)]
102pub struct TargetInput {
103    pub name: String,
104    pub default: Const,
105    pub invert_param: Option<usize>,
106    pub range: Range<usize>,
107}
108
109impl TargetInput {
110    pub fn len(&self) -> usize {
111        self.default.len()
112    }
113}
114
115#[derive(Debug, Clone, PartialEq, Eq)]
116pub struct TargetOutput {
117    pub name: String,
118    pub range: Range<usize>,
119}
120
121impl TargetOutput {
122    pub fn len(&self) -> usize {
123        self.range.len()
124    }
125}
126
127#[derive(Debug, Clone, PartialEq, Eq)]
128pub struct TargetIo {
129    pub name: String,
130    pub range: Range<usize>,
131}
132
133impl TargetIo {
134    pub fn len(&self) -> usize {
135        self.range.len()
136    }
137}
138
139#[derive(Debug, Clone, Copy, PartialEq, Eq)]
140pub enum TargetCellPurity {
141    Pure,
142    HasState,
143    HasEffects,
144}
145
146#[derive(Debug, Clone, PartialEq, Eq)]
147pub struct TargetPrototype {
148    pub purity: TargetCellPurity,
149    pub params: Vec<TargetParam>,
150    pub params_by_name: BTreeMap<String, usize>,
151    pub inputs: Vec<TargetInput>,
152    pub inputs_by_name: BTreeMap<String, usize>,
153    pub input_len: usize,
154    pub outputs: Vec<TargetOutput>,
155    pub outputs_by_name: BTreeMap<String, usize>,
156    pub output_len: usize,
157    pub ios: Vec<TargetIo>,
158    pub ios_by_name: BTreeMap<String, usize>,
159    pub io_len: usize,
160}
161
162impl TargetPrototype {
163    fn new(purity: TargetCellPurity) -> TargetPrototype {
164        TargetPrototype {
165            purity,
166            params: vec![],
167            params_by_name: Default::default(),
168            inputs: vec![],
169            inputs_by_name: Default::default(),
170            input_len: 0,
171            outputs: vec![],
172            outputs_by_name: Default::default(),
173            output_len: 0,
174            ios: vec![],
175            ios_by_name: Default::default(),
176            io_len: 0,
177        }
178    }
179
180    pub fn new_pure() -> TargetPrototype {
181        Self::new(TargetCellPurity::Pure)
182    }
183
184    pub fn new_has_state() -> TargetPrototype {
185        Self::new(TargetCellPurity::HasState)
186    }
187
188    pub fn new_has_effects() -> TargetPrototype {
189        Self::new(TargetCellPurity::HasEffects)
190    }
191
192    fn add_param_raw(mut self, name: impl Into<String>, kind: TargetParamKind, default: ParamValue) -> Self {
193        let name = name.into();
194        let index = self.params.len();
195        self.params_by_name.insert(name.clone(), index);
196        self.params.push(TargetParam { name, kind, default, index });
197        self
198    }
199
200    pub fn add_param_bits(self, name: impl Into<String>, default: impl Into<Const>) -> Self {
201        let default = default.into();
202        self.add_param_raw(name, TargetParamKind::Bits(default.len()), ParamValue::Const(default))
203    }
204
205    pub fn add_param_bool(self, name: impl Into<String>, default: bool) -> Self {
206        self.add_param_raw(name, TargetParamKind::Bool, ParamValue::Const(Trit::from(default).into()))
207    }
208
209    pub fn add_param_int_enum(self, name: impl Into<String>, variants: &[i64]) -> Self {
210        let variants = variants.to_vec();
211        let default = variants[0];
212        self.add_param_raw(name, TargetParamKind::IntEnum(variants), ParamValue::Int(default))
213    }
214
215    pub fn add_param_string_enum(self, name: impl Into<String>, variants: &[impl AsRef<str>]) -> Self {
216        let variants = Vec::from_iter(variants.iter().map(|s| s.as_ref().to_owned()));
217        let default = variants[0].clone();
218        self.add_param_raw(name, TargetParamKind::StringEnum(variants), ParamValue::String(default))
219    }
220
221    fn add_input_raw(
222        mut self,
223        name: impl Into<String>,
224        default: impl Into<Const>,
225        invert_param: Option<usize>,
226    ) -> Self {
227        let default = default.into();
228        let range = self.input_len..self.input_len + default.len();
229        self.input_len += default.len();
230        let name = name.into();
231        self.inputs_by_name.insert(name.clone(), self.inputs.len());
232        self.inputs.push(TargetInput { name, default, invert_param, range });
233        self
234    }
235
236    pub fn add_input(self, name: impl Into<String>, default: impl Into<Const>) -> Self {
237        self.add_input_raw(name, default, None)
238    }
239
240    pub fn add_input_invertible(
241        self,
242        name: impl Into<String>,
243        default: impl Into<Const>,
244        invert_param: impl AsRef<str>,
245    ) -> Self {
246        let invert_param = self.params_by_name[invert_param.as_ref()];
247        let default = default.into();
248        match &self.params[invert_param].kind {
249            TargetParamKind::Bits(width) if *width == default.len() => (),
250            TargetParamKind::Bool if default.len() == 1 => (),
251            _ => panic!("invalid kind for inversion parameter {invert_param:?}"),
252        }
253        self.add_input_raw(name, default, Some(invert_param))
254    }
255
256    pub fn add_output(mut self, name: impl Into<String>, width: usize) -> Self {
257        let range = self.output_len..self.output_len + width;
258        self.output_len += width;
259        let name = name.into();
260        self.outputs_by_name.insert(name.clone(), self.outputs.len());
261        self.outputs.push(TargetOutput { name, range });
262        self
263    }
264
265    pub fn add_io(mut self, name: impl Into<String>, width: usize) -> Self {
266        let range = self.io_len..self.io_len + width;
267        self.io_len += width;
268        let name = name.into();
269        self.ios_by_name.insert(name.clone(), self.ios.len());
270        self.ios.push(TargetIo { name, range });
271        self
272    }
273
274    pub fn get_param(&self, name: &str) -> Option<&TargetParam> {
275        self.params_by_name.get(name).map(|&index| &self.params[index])
276    }
277
278    pub fn get_input(&self, name: &str) -> Option<&TargetInput> {
279        self.inputs_by_name.get(name).map(|&index| &self.inputs[index])
280    }
281
282    pub fn get_output(&self, name: &str) -> Option<&TargetOutput> {
283        self.outputs_by_name.get(name).map(|&index| &self.outputs[index])
284    }
285
286    pub fn get_io(&self, name: &str) -> Option<&TargetIo> {
287        self.ios_by_name.get(name).map(|&index| &self.ios[index])
288    }
289
290    pub fn apply_param(&self, target_cell: &mut TargetCell, name: impl AsRef<str>, value: impl Into<ParamValue>) {
291        let name = name.as_ref();
292        if let Some(TargetParam { index, .. }) = self.get_param(name) {
293            target_cell.params[*index] = value.into();
294        } else {
295            panic!("parameter {:?} does not exist for target cell", name);
296        }
297    }
298
299    pub fn apply_input<'a>(
300        &self,
301        target_cell: &mut TargetCell,
302        name: impl AsRef<str>,
303        value: impl Into<Cow<'a, Value>>,
304    ) {
305        let (name, value) = (name.as_ref(), value.into());
306        if let Some(TargetInput { range, .. }) = self.get_input(name) {
307            target_cell.inputs[range.clone()].copy_from_slice(&value[..]);
308        } else {
309            panic!("input {:?} does not exist for target cell", name);
310        }
311    }
312
313    pub fn apply_io<'a>(
314        &self,
315        target_cell: &mut TargetCell,
316        name: impl AsRef<str>,
317        value: impl Into<Cow<'a, IoValue>>,
318    ) {
319        let (name, value) = (name.as_ref(), value.into());
320        if let Some(TargetIo { range, .. }) = self.get_io(name) {
321            target_cell.ios[range.clone()].copy_from_slice(&value[..]);
322        } else {
323            panic!("input {:?} does not exist for target cell", name);
324        }
325    }
326
327    pub fn extract_param<'a>(&self, target_cell: &'a TargetCell, name: impl AsRef<str>) -> &'a ParamValue {
328        let name = name.as_ref();
329        if let Some(TargetParam { index, .. }) = self.get_param(name) {
330            &target_cell.params[*index]
331        } else {
332            panic!("param {:?} does not exist for target cell", name);
333        }
334    }
335
336    pub fn extract_param_bool(&self, target_cell: &TargetCell, name: impl AsRef<str>) -> bool {
337        let name = name.as_ref();
338        if let Some(TargetParam { index, kind, .. }) = self.get_param(name) {
339            assert_eq!(*kind, TargetParamKind::Bool);
340            let ParamValue::Const(ref value) = target_cell.params[*index] else { unreachable!() };
341            value[0] == Trit::One
342        } else {
343            panic!("param {:?} does not exist for target cell", name);
344        }
345    }
346
347    pub fn extract_input(&self, target_cell: &TargetCell, name: impl AsRef<str>) -> Value {
348        let name = name.as_ref();
349        if let Some(TargetInput { range, .. }) = self.get_input(name) {
350            target_cell.inputs.slice(range.clone())
351        } else {
352            panic!("input {:?} does not exist for target cell", name);
353        }
354    }
355
356    pub fn extract_output(&self, target_cell_output: &Value, name: impl AsRef<str>) -> Value {
357        let name = name.as_ref();
358        if let Some(TargetOutput { range, .. }) = self.get_output(name) {
359            target_cell_output.slice(range.clone())
360        } else {
361            panic!("output {:?} does not exist for target cell", name);
362        }
363    }
364
365    pub fn target_cell_to_instance(&self, cell: &TargetCell) -> Instance {
366        let mut result = Instance::new(cell.kind.clone());
367        for (index, param) in self.params.iter().enumerate() {
368            result.params.insert(param.name.clone(), cell.params[index].clone());
369        }
370        for input in &self.inputs {
371            result.inputs.insert(input.name.clone(), cell.inputs.slice(input.range.clone()));
372        }
373        for output in &self.outputs {
374            result.outputs.insert(output.name.clone(), output.range.clone());
375        }
376        for io in &self.ios {
377            result.ios.insert(io.name.clone(), cell.ios.slice(io.range.clone()));
378        }
379        result
380    }
381
382    pub fn instance_to_target_cell(
383        &self,
384        design: &Design,
385        instance: &Instance,
386        instance_output: Value,
387    ) -> Result<(TargetCell, Value), TargetCellImportError> {
388        let mut target_cell = TargetCell::new(instance.kind.clone(), self);
389        for (name, value) in &instance.params {
390            let param = self.get_param(name).ok_or_else(|| TargetCellImportError::UnknownParameter(name.clone()))?;
391            let Some(value) = param.kind.cast(value) else {
392                return Err(TargetCellImportError::ParameterValueInvalid(name.clone(), value.clone()));
393            };
394            target_cell.params[param.index] = value;
395        }
396        for (name, value) in &instance.inputs {
397            let input = self.get_input(name).ok_or_else(|| TargetCellImportError::UnknownInput(name.clone()))?;
398            if value.len() != input.len() {
399                return Err(TargetCellImportError::InputSizeMismatch(name.clone()));
400            }
401            target_cell.inputs[input.range.clone()].copy_from_slice(&value[..]);
402        }
403        for (name, value) in &instance.ios {
404            let io = self.get_io(name).ok_or_else(|| TargetCellImportError::UnknownIo(name.clone()))?;
405            if value.len() != io.len() {
406                return Err(TargetCellImportError::IoSizeMismatch(name.clone()));
407            }
408            target_cell.ios[io.range.clone()].copy_from_slice(&value[..]);
409        }
410        let mut target_output = design.add_void(self.output_len);
411        for (name, range) in &instance.outputs {
412            let output = self.get_output(name).ok_or_else(|| TargetCellImportError::UnknownOutput(name.clone()))?;
413            if range.len() != output.len() {
414                return Err(TargetCellImportError::OutputSizeMismatch(name.clone()));
415            }
416            target_output[output.range.clone()].copy_from_slice(&instance_output[range.clone()]);
417        }
418        Ok((target_cell, target_output))
419    }
420}
421
422#[derive(Debug, Clone)]
423pub enum TargetCellImportError {
424    UnknownParameter(String),
425    ParameterTypeMismatch(String),
426    ParameterValueInvalid(String, ParamValue),
427    UnknownInput(String),
428    InputSizeMismatch(String),
429    UnknownOutput(String),
430    OutputSizeMismatch(String),
431    UnknownIo(String),
432    IoSizeMismatch(String),
433}
434
435impl Display for TargetCellImportError {
436    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
437        match self {
438            TargetCellImportError::UnknownParameter(name) => write!(f, "unknown parameter {name:?}"),
439            TargetCellImportError::ParameterTypeMismatch(name) => write!(f, "type mismatch for parameter {name:?}"),
440            TargetCellImportError::ParameterValueInvalid(name, value) => {
441                let value = match value {
442                    ParamValue::Const(value) => format!("{value}"),
443                    ParamValue::Int(value) => format!("{value}"),
444                    ParamValue::Float(value) => format!("{value}"),
445                    ParamValue::String(value) => format!("{value:?}"),
446                };
447                write!(f, "invalid value {value} for parameter {name:?}")
448            }
449            TargetCellImportError::UnknownInput(name) => write!(f, "unknown input {name:?}"),
450            TargetCellImportError::InputSizeMismatch(name) => write!(f, "size mismatch for input {name:?}"),
451            TargetCellImportError::UnknownOutput(name) => write!(f, "unknown output {name:?}"),
452            TargetCellImportError::OutputSizeMismatch(name) => write!(f, "size mismatch for output {name:?}"),
453            TargetCellImportError::UnknownIo(name) => write!(f, "unknown io {name:?}"),
454            TargetCellImportError::IoSizeMismatch(name) => write!(f, "size mismatch for io {name:?}"),
455        }
456    }
457}
458
459impl Error for TargetCellImportError {}
460
461#[derive(Debug, Clone)]
462pub struct TargetImportError {
463    cell_index: usize,
464    pub cause: TargetCellImportError,
465}
466
467impl TargetImportError {
468    pub fn new(cell_ref: CellRef, cause: TargetCellImportError) -> TargetImportError {
469        TargetImportError { cell_index: cell_ref.debug_index(), cause }
470    }
471
472    pub fn unknown_parameter(cell_ref: CellRef, name: impl Into<String>) -> TargetImportError {
473        Self::new(cell_ref, TargetCellImportError::UnknownParameter(name.into()))
474    }
475
476    pub fn parameter_type_mismatch(cell_ref: CellRef, name: impl Into<String>) -> TargetImportError {
477        Self::new(cell_ref, TargetCellImportError::ParameterTypeMismatch(name.into()))
478    }
479
480    pub fn parameter_value_invalid(cell_ref: CellRef, name: impl Into<String>, value: ParamValue) -> TargetImportError {
481        Self::new(cell_ref, TargetCellImportError::ParameterValueInvalid(name.into(), value))
482    }
483
484    pub fn unknown_input(cell_ref: CellRef, name: impl Into<String>) -> TargetImportError {
485        Self::new(cell_ref, TargetCellImportError::UnknownInput(name.into()))
486    }
487
488    pub fn input_size_mismatch(cell_ref: CellRef, name: impl Into<String>) -> TargetImportError {
489        Self::new(cell_ref, TargetCellImportError::InputSizeMismatch(name.into()))
490    }
491
492    pub fn unknown_output(cell_ref: CellRef, name: impl Into<String>) -> TargetImportError {
493        Self::new(cell_ref, TargetCellImportError::UnknownOutput(name.into()))
494    }
495
496    pub fn output_size_mismatch(cell_ref: CellRef, name: impl Into<String>) -> TargetImportError {
497        Self::new(cell_ref, TargetCellImportError::OutputSizeMismatch(name.into()))
498    }
499
500    pub fn unknown_io(cell_ref: CellRef, name: impl Into<String>) -> TargetImportError {
501        Self::new(cell_ref, TargetCellImportError::UnknownIo(name.into()))
502    }
503
504    pub fn io_size_mismatch(cell_ref: CellRef, name: impl Into<String>) -> TargetImportError {
505        Self::new(cell_ref, TargetCellImportError::IoSizeMismatch(name.into()))
506    }
507}
508
509impl Display for TargetImportError {
510    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
511        write!(f, "error importing cell %{}: {}", self.cell_index, self.cause)
512    }
513}
514
515impl Error for TargetImportError {}
516
517#[derive(Debug, Clone)]
518pub struct UnknownTargetError(String);
519
520impl Display for UnknownTargetError {
521    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
522        write!(f, "unknown target {:?} (known targets:", self.0)?;
523        for target in REGISTRY.lock().unwrap().keys() {
524            write!(f, " {target}")?;
525        }
526        write!(f, ")")
527    }
528}
529
530impl Error for UnknownTargetError {}
531
532// I'm sorry! I'm sorry!! I'm trying to remove this but trait aliases aren't stable yet...
533static REGISTRY: Mutex<
534    BTreeMap<String, Box<dyn Fn(BTreeMap<String, String>) -> Result<Arc<dyn Target>, Box<dyn Error>> + Send>>,
535> = Mutex::new(BTreeMap::new());
536
537pub fn register_target(
538    name: impl Into<String>,
539    builder: impl Fn(BTreeMap<String, String>) -> Result<Arc<dyn Target>, Box<dyn Error>> + Send + 'static,
540) {
541    let mut registry = REGISTRY.lock().unwrap();
542    assert!(registry.insert(name.into(), Box::new(builder)).is_none());
543}
544
545pub fn create_target(name: &str, options: BTreeMap<String, String>) -> Result<Arc<dyn Target>, Box<dyn Error>> {
546    let registry = REGISTRY.lock().unwrap();
547    match registry.get(name).map(|builder| builder(options)) {
548        Some(target) => target,
549        None => Err(UnknownTargetError(name.into()))?,
550    }
551}