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 fn name(&self) -> &str;
13
14 fn options(&self) -> BTreeMap<String, String>;
18
19 fn prototype(&self, name: &str) -> Option<&TargetPrototype>;
22
23 fn validate(&self, design: &Design, cell: &TargetCell);
26
27 fn import(&self, design: &mut Design) -> Result<(), TargetImportError>;
29
30 fn export(&self, design: &mut Design);
32
33 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
532static 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}