prjunnamed_yosys_json/
yosys.rs

1use jzon::{object, JsonValue};
2use std::collections::{btree_map, BTreeMap};
3
4use prjunnamed_netlist::{Const, ParamValue, Trit};
5
6#[derive(Debug)]
7pub struct SyntaxError(JsonValue);
8
9impl std::fmt::Display for SyntaxError {
10    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
11        write!(f, "syntax error near: {}", self.0)
12    }
13}
14
15impl std::error::Error for SyntaxError {}
16
17#[derive(Debug)]
18pub struct MetadataTypeError;
19
20impl std::fmt::Display for MetadataTypeError {
21    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
22        write!(f, "unexpected metadata type")
23    }
24}
25
26impl std::error::Error for MetadataTypeError {}
27
28#[derive(Debug, Clone, Copy)]
29pub enum Bit {
30    Zero,
31    One,
32    Undef,
33    HiZ,
34    Net(usize),
35}
36
37impl From<Trit> for Bit {
38    fn from(value: Trit) -> Self {
39        match value {
40            Trit::Undef => Bit::Undef,
41            Trit::Zero => Bit::Zero,
42            Trit::One => Bit::One,
43        }
44    }
45}
46
47impl TryFrom<JsonValue> for Bit {
48    type Error = SyntaxError;
49
50    fn try_from(value: JsonValue) -> Result<Self, Self::Error> {
51        match value.as_str() {
52            Some("0") => Ok(Self::Zero),
53            Some("1") => Ok(Self::One),
54            Some("x") => Ok(Self::Undef),
55            Some("z") => Ok(Self::HiZ),
56            Some(_) => Err(SyntaxError(value)),
57            None => match value.as_usize() {
58                Some(index) => Ok(Bit::Net(index)),
59                None => Err(SyntaxError(value)),
60            },
61        }
62    }
63}
64
65impl From<Bit> for JsonValue {
66    fn from(value: Bit) -> Self {
67        match value {
68            Bit::Zero => "0".into(),
69            Bit::One => "1".into(),
70            Bit::Undef => "x".into(),
71            Bit::HiZ => "z".into(),
72            Bit::Net(index) => index.into(),
73        }
74    }
75}
76
77#[derive(Debug, Clone)]
78pub struct BitVector(pub Vec<Bit>);
79
80impl BitVector {
81    pub fn iter(&self) -> std::slice::Iter<'_, Bit> {
82        self.0.iter()
83    }
84
85    pub fn len(&self) -> usize {
86        self.0.len()
87    }
88
89    pub fn concat(&self, other: &BitVector) -> Self {
90        let mut bits = self.0.clone();
91        bits.extend(&other.0);
92        BitVector(bits)
93    }
94}
95
96impl From<Bit> for BitVector {
97    fn from(value: Bit) -> Self {
98        BitVector(vec![value])
99    }
100}
101
102impl From<Const> for BitVector {
103    fn from(value: Const) -> Self {
104        BitVector(value.iter().map(Into::into).collect::<Vec<_>>())
105    }
106}
107
108impl TryFrom<JsonValue> for BitVector {
109    type Error = SyntaxError;
110
111    fn try_from(mut value: JsonValue) -> Result<Self, Self::Error> {
112        if value.is_array() {
113            let mut bits = vec![];
114            for bit_value in value.members_mut() {
115                bits.push(Bit::try_from(bit_value.take())?);
116            }
117            Ok(BitVector(bits))
118        } else {
119            Err(SyntaxError(value))
120        }
121    }
122}
123
124impl From<BitVector> for JsonValue {
125    fn from(value: BitVector) -> JsonValue {
126        JsonValue::Array(value.0.iter().copied().map(JsonValue::from).collect::<Vec<_>>())
127    }
128}
129
130#[derive(Debug, Clone)]
131pub enum MetadataValue {
132    String(String),
133    Const(Const),
134}
135
136impl MetadataValue {
137    pub fn as_const(&self) -> Result<Const, MetadataTypeError> {
138        match self {
139            Self::Const(value) => Ok(value.clone()),
140            _ => Err(MetadataTypeError),
141        }
142    }
143
144    pub fn as_i32(&self) -> Result<i32, MetadataTypeError> {
145        match self {
146            Self::Const(value) if value.len() == 32 => {
147                let mut i32_value = 0;
148                for (index, trit) in value.iter().enumerate() {
149                    match trit {
150                        Trit::One => i32_value |= 1 << index,
151                        Trit::Zero => (),
152                        Trit::Undef => return Err(MetadataTypeError),
153                    }
154                }
155                Ok(i32_value)
156            }
157            _ => Err(MetadataTypeError),
158        }
159    }
160
161    pub fn as_bool(&self) -> Result<bool, MetadataTypeError> {
162        match self {
163            Self::Const(value) => match value.try_into() {
164                Ok(0u64) => Ok(false),
165                Ok(1u64) => Ok(true),
166                _ => Err(MetadataTypeError),
167            },
168            _ => Err(MetadataTypeError),
169        }
170    }
171}
172
173impl From<Const> for MetadataValue {
174    fn from(value: Const) -> Self {
175        MetadataValue::Const(value)
176    }
177}
178
179macro_rules! metadata_value_from_integral {
180    ($int:ty) => {
181        impl From<$int> for MetadataValue {
182            fn from(value: $int) -> Self {
183                let mut trits = vec![];
184                for index in 0..<$int>::BITS {
185                    trits.push(if value & (1 << index) != 0 { Trit::One } else { Trit::Zero });
186                }
187                MetadataValue::Const(trits.into())
188            }
189        }
190    };
191}
192
193metadata_value_from_integral!(u64);
194metadata_value_from_integral!(i64);
195metadata_value_from_integral!(u32);
196metadata_value_from_integral!(i32);
197
198impl From<usize> for MetadataValue {
199    fn from(value: usize) -> Self {
200        (value as i32).into()
201    }
202}
203
204impl From<bool> for MetadataValue {
205    fn from(value: bool) -> Self {
206        if value { 1i32 } else { 0 }.into()
207    }
208}
209
210impl From<String> for MetadataValue {
211    fn from(value: String) -> Self {
212        MetadataValue::String(value)
213    }
214}
215
216impl From<&String> for MetadataValue {
217    fn from(value: &String) -> Self {
218        MetadataValue::String(value.to_owned())
219    }
220}
221
222impl From<&str> for MetadataValue {
223    fn from(value: &str) -> Self {
224        MetadataValue::String(value.to_owned())
225    }
226}
227
228impl From<ParamValue> for MetadataValue {
229    fn from(value: ParamValue) -> Self {
230        match value {
231            ParamValue::Const(value) => value.into(),
232            ParamValue::Int(value) => value.into(),
233            ParamValue::String(value) => value.into(),
234            ParamValue::Float(_) => {
235                unimplemented!("Yosys JSON does not define serialization for floating point parameters")
236            }
237        }
238    }
239}
240
241impl From<&ParamValue> for MetadataValue {
242    fn from(value: &ParamValue) -> Self {
243        value.clone().into()
244    }
245}
246
247enum MetadataValueClass {
248    Bits,
249    BitsAndSpaces,
250    Other,
251}
252
253impl MetadataValueClass {
254    fn compute(value: &str) -> MetadataValueClass {
255        let mut class = MetadataValueClass::Bits;
256        for char in value.chars() {
257            match (&class, char) {
258                (MetadataValueClass::Bits, '0' | '1' | 'x' | 'z') => (),
259                (MetadataValueClass::BitsAndSpaces, ' ') => (),
260                (MetadataValueClass::Bits, ' ') => class = MetadataValueClass::BitsAndSpaces,
261                _ => class = MetadataValueClass::Other,
262            }
263        }
264        class
265    }
266}
267
268impl TryFrom<JsonValue> for MetadataValue {
269    type Error = SyntaxError;
270
271    fn try_from(value: JsonValue) -> Result<Self, Self::Error> {
272        if let Some(value) = value.as_str() {
273            Ok(match MetadataValueClass::compute(value) {
274                MetadataValueClass::Bits => MetadataValue::Const(
275                    value
276                        .chars()
277                        .rev()
278                        .map(|char| match char {
279                            'x' => Trit::Undef,
280                            '0' => Trit::Zero,
281                            '1' => Trit::One,
282                            _ => unreachable!(),
283                        })
284                        .collect::<Vec<_>>()
285                        .into(),
286                ),
287                MetadataValueClass::BitsAndSpaces => MetadataValue::String(value.strip_suffix(" ").unwrap().to_owned()),
288                MetadataValueClass::Other => MetadataValue::String(value.to_owned()),
289            })
290        } else {
291            Err(SyntaxError(value))
292        }
293    }
294}
295
296impl From<MetadataValue> for JsonValue {
297    fn from(value: MetadataValue) -> JsonValue {
298        match value {
299            MetadataValue::String(value) => match MetadataValueClass::compute(&value) {
300                MetadataValueClass::Bits => value.into(),
301                MetadataValueClass::BitsAndSpaces => (value + " ").into(),
302                MetadataValueClass::Other => value.into(),
303            },
304            MetadataValue::Const(value) => value
305                .iter()
306                .rev()
307                .map(|trit| match trit {
308                    Trit::Undef => "x",
309                    Trit::Zero => "0",
310                    Trit::One => "1",
311                })
312                .collect::<String>()
313                .into(),
314        }
315    }
316}
317
318#[derive(Debug)]
319pub struct Metadata(pub BTreeMap<String, MetadataValue>);
320
321impl Metadata {
322    pub fn new() -> Metadata {
323        Metadata(BTreeMap::new())
324    }
325
326    pub fn iter(&self) -> btree_map::Iter<'_, String, MetadataValue> {
327        self.0.iter()
328    }
329
330    pub fn get(&self, key: &str) -> Option<&MetadataValue> {
331        self.0.get(key)
332    }
333
334    pub fn add(&mut self, key: &str, value: impl ToOwned<Owned = MetadataValue>) {
335        self.0.insert(key.to_owned(), value.to_owned());
336    }
337
338    pub fn extend(&mut self, values: impl IntoIterator<Item = (String, MetadataValue)>) {
339        self.0.extend(values);
340    }
341}
342
343impl TryFrom<JsonValue> for Metadata {
344    type Error = SyntaxError;
345
346    fn try_from(mut value: JsonValue) -> Result<Self, Self::Error> {
347        if value.is_object() {
348            let mut entries = BTreeMap::new();
349            for (name, value) in value.entries_mut() {
350                entries.insert(name.to_owned(), value.take().try_into()?);
351            }
352            Ok(Metadata(entries))
353        } else {
354            Err(SyntaxError(value))
355        }
356    }
357}
358
359impl From<Metadata> for JsonValue {
360    fn from(value: Metadata) -> JsonValue {
361        value.0.into()
362    }
363}
364
365#[derive(Debug)]
366pub struct Map<V>(pub BTreeMap<String, V>);
367
368impl<V> Map<V> {
369    pub fn new() -> Map<V> {
370        Map(BTreeMap::new())
371    }
372
373    pub fn iter(&self) -> btree_map::Iter<'_, String, V> {
374        self.0.iter()
375    }
376
377    pub fn get(&self, key: &str) -> Option<&V> {
378        self.0.get(key)
379    }
380
381    pub fn contains_key(&self, key: &str) -> bool {
382        self.0.contains_key(key)
383    }
384
385    pub fn add(&mut self, key: &str, value: V) {
386        self.0.insert(key.to_owned(), value);
387    }
388}
389
390impl<V> From<BTreeMap<String, V>> for Map<V> {
391    fn from(value: BTreeMap<String, V>) -> Self {
392        Map(value)
393    }
394}
395
396impl<V: TryFrom<JsonValue, Error = SyntaxError>> TryFrom<JsonValue> for Map<V> {
397    type Error = SyntaxError;
398
399    fn try_from(mut value: JsonValue) -> Result<Self, Self::Error> {
400        if value.is_object() {
401            let mut entries = BTreeMap::new();
402            for (name, value) in value.entries_mut() {
403                entries.insert(name.to_owned(), value.take().try_into()?);
404            }
405            Ok(Map(entries))
406        } else {
407            Err(SyntaxError(value))
408        }
409    }
410}
411
412impl<V: Into<JsonValue>> From<Map<V>> for JsonValue {
413    fn from(value: Map<V>) -> JsonValue {
414        value.0.into()
415    }
416}
417
418#[derive(Debug, Clone, Copy, PartialEq, Eq)]
419pub enum PortDirection {
420    Input,
421    Output,
422    Inout,
423}
424
425impl TryFrom<JsonValue> for PortDirection {
426    type Error = SyntaxError;
427
428    fn try_from(value: JsonValue) -> Result<Self, Self::Error> {
429        match value.as_str() {
430            Some("input") => Ok(PortDirection::Input),
431            Some("output") => Ok(PortDirection::Output),
432            Some("inout") => Ok(PortDirection::Inout),
433            _ => Err(SyntaxError(value)),
434        }
435    }
436}
437
438impl From<PortDirection> for JsonValue {
439    fn from(value: PortDirection) -> JsonValue {
440        match value {
441            PortDirection::Input => "input".into(),
442            PortDirection::Output => "output".into(),
443            PortDirection::Inout => "inout".into(),
444        }
445    }
446}
447
448#[derive(Debug)]
449pub struct PortDetails {
450    pub direction: PortDirection,
451    pub bits: BitVector,
452    pub offset: usize,
453    pub upto: bool,
454    pub signed: bool,
455}
456
457impl PortDetails {
458    pub fn new(direction: PortDirection, bits: BitVector) -> PortDetails {
459        PortDetails { direction, bits, offset: 0, upto: false, signed: false }
460    }
461}
462
463impl TryFrom<JsonValue> for PortDetails {
464    type Error = SyntaxError;
465
466    fn try_from(mut value: JsonValue) -> Result<Self, Self::Error> {
467        let direction = PortDirection::try_from(value["direction"].take())?;
468        let bits = BitVector::try_from(value["bits"].take())?;
469        let offset = value["offset"].as_usize().unwrap_or(0);
470        let upto = value["upto"].as_usize().unwrap_or(0) != 0;
471        let signed = value["signed"].as_usize().unwrap_or(0) != 0;
472        Ok(PortDetails { direction, bits, offset, upto, signed })
473    }
474}
475
476impl From<PortDetails> for JsonValue {
477    fn from(value: PortDetails) -> JsonValue {
478        let mut json = object! {
479            direction: value.direction,
480            bits: value.bits,
481        };
482        if value.offset != 0 {
483            json["offset"] = value.offset.into();
484        }
485        if value.upto {
486            json["upto"] = 1.into();
487        }
488        if value.signed {
489            json["signed"] = 1.into();
490        }
491        json
492    }
493}
494
495#[derive(Debug)]
496pub struct CellDetails {
497    pub hide_name: bool,
498    pub type_: String,
499    pub parameters: Metadata,
500    pub attributes: Metadata,
501    pub port_directions: Map<PortDirection>,
502    pub connections: Map<BitVector>,
503}
504
505impl CellDetails {
506    pub fn new(type_: &str) -> CellDetails {
507        CellDetails {
508            hide_name: false,
509            type_: type_.into(),
510            parameters: Metadata::new(),
511            attributes: Metadata::new(),
512            port_directions: Map::new(),
513            connections: Map::new(),
514        }
515    }
516
517    pub fn attr(mut self, name: &str, value: impl Into<MetadataValue>) -> CellDetails {
518        self.attributes.add(name, value.into());
519        self
520    }
521
522    pub fn attrs(mut self, attrs: impl IntoIterator<Item = (String, MetadataValue)>) -> CellDetails {
523        self.attributes.extend(attrs);
524        self
525    }
526
527    pub fn param(mut self, name: &str, value: impl Into<MetadataValue>) -> CellDetails {
528        self.parameters.add(name, value.into());
529        self
530    }
531
532    pub fn port(mut self, name: &str, port_direction: PortDirection, connection: impl Into<BitVector>) -> CellDetails {
533        self.port_directions.add(name, port_direction);
534        self.connections.add(name, connection.into());
535        self
536    }
537
538    pub fn input(self, name: &str, connection: impl Into<BitVector>) -> CellDetails {
539        self.port(name, PortDirection::Input, connection)
540    }
541
542    pub fn output(self, name: &str, connection: impl Into<BitVector>) -> CellDetails {
543        self.port(name, PortDirection::Output, connection)
544    }
545
546    pub fn inout(self, name: &str, connection: impl Into<BitVector>) -> CellDetails {
547        self.port(name, PortDirection::Inout, connection)
548    }
549
550    pub fn add_to(mut self, name: &str, module: &mut Module) {
551        let mut name = name;
552        let hdlname: String;
553        if let Some(MetadataValue::String(value)) = self.attributes.0.get("hdlname") {
554            hdlname = value.replace(' ', ".");
555            if !module.cells.contains_key(value) {
556                name = &hdlname;
557            }
558        }
559        assert!(!module.cells.contains_key(name));
560        self.hide_name = name.starts_with('$');
561        module.cells.add(name, self)
562    }
563}
564
565impl TryFrom<JsonValue> for CellDetails {
566    type Error = SyntaxError;
567
568    fn try_from(mut value: JsonValue) -> Result<Self, Self::Error> {
569        let hide_name = value["hide_name"].as_usize().unwrap_or(0) != 0;
570        let type_ = value["type"].as_str().map(|s| s.to_owned()).ok_or(SyntaxError(value["type"].take()))?;
571        let parameters = Metadata::try_from(value["parameters"].take())?;
572        let attributes = Metadata::try_from(value["attributes"].take())?;
573        let port_directions = Map::<PortDirection>::try_from(value["port_directions"].take())?;
574        let connections = Map::<BitVector>::try_from(value["connections"].take())?;
575        Ok(CellDetails { hide_name, type_, parameters, attributes, port_directions, connections })
576    }
577}
578
579impl From<CellDetails> for JsonValue {
580    fn from(value: CellDetails) -> JsonValue {
581        object! {
582            hide_name: if value.hide_name { 1 } else { 0 },
583            type: value.type_,
584            parameters: value.parameters,
585            attributes: value.attributes,
586            port_directions: value.port_directions,
587            connections: value.connections,
588        }
589    }
590}
591
592#[derive(Debug)]
593pub struct MemoryDetails {
594    pub hide_name: bool,
595    pub attributes: Metadata,
596    pub width: usize,
597    pub start_offset: usize,
598    pub size: usize,
599}
600
601impl TryFrom<JsonValue> for MemoryDetails {
602    type Error = SyntaxError;
603
604    fn try_from(mut value: JsonValue) -> Result<Self, Self::Error> {
605        let hide_name = value["hide_name"].as_usize().unwrap_or(0) != 0;
606        let attributes = Metadata::try_from(value["attributes"].take())?;
607        let width = value["width"].as_usize().ok_or(SyntaxError(value["width"].take()))?;
608        let start_offset = value["start_offset"].as_usize().ok_or(SyntaxError(value["start_offset"].take()))?;
609        let size = value["size"].as_usize().ok_or(SyntaxError(value["size"].take()))?;
610        Ok(MemoryDetails { hide_name, attributes, width, start_offset, size })
611    }
612}
613
614impl From<MemoryDetails> for JsonValue {
615    fn from(value: MemoryDetails) -> JsonValue {
616        object! {
617            hide_name: if value.hide_name { 1 } else { 0 },
618            attributes: value.attributes,
619            width: value.width,
620            start_offset: value.start_offset,
621            size: value.size,
622        }
623    }
624}
625
626#[derive(Debug)]
627pub struct NetDetails {
628    pub hide_name: bool,
629    pub attributes: Metadata,
630    pub bits: BitVector,
631    pub offset: usize,
632    pub upto: bool,
633    pub signed: bool,
634}
635
636impl NetDetails {
637    pub fn new(bits: impl Into<BitVector>) -> NetDetails {
638        NetDetails {
639            hide_name: false,
640            attributes: Metadata::new(),
641            bits: bits.into(),
642            offset: 0,
643            upto: false,
644            signed: false,
645        }
646    }
647
648    pub fn attr(mut self, name: &str, value: impl Into<MetadataValue>) -> NetDetails {
649        self.attributes.add(name, value.into());
650        self
651    }
652
653    pub fn attrs(mut self, attrs: impl IntoIterator<Item = (String, MetadataValue)>) -> NetDetails {
654        self.attributes.extend(attrs);
655        self
656    }
657
658    pub fn add_to(mut self, name: &str, module: &mut Module) {
659        assert!(!module.netnames.contains_key(name));
660        self.hide_name = name.starts_with('$');
661        module.netnames.add(name, self)
662    }
663}
664
665impl TryFrom<JsonValue> for NetDetails {
666    type Error = SyntaxError;
667
668    fn try_from(mut value: JsonValue) -> Result<Self, Self::Error> {
669        let hide_name = value["hide_name"].as_usize().unwrap_or(0) != 0;
670        let attributes = Metadata::try_from(value["attributes"].take())?;
671        let bits = BitVector::try_from(value["bits"].take())?;
672        let offset = value["offset"].as_usize().unwrap_or(0);
673        let upto = value["upto"].as_usize().unwrap_or(0) != 0;
674        let signed = value["signed"].as_usize().unwrap_or(0) != 0;
675        Ok(NetDetails { hide_name, attributes, bits, offset, upto, signed })
676    }
677}
678
679impl From<NetDetails> for JsonValue {
680    fn from(value: NetDetails) -> JsonValue {
681        let mut json = object! {
682            hide_name: if value.hide_name { 1 } else { 0 },
683            attributes: value.attributes,
684            bits: value.bits,
685        };
686        if value.offset != 0 {
687            json["offset"] = value.offset.into();
688        }
689        if value.upto {
690            json["upto"] = 1.into();
691        }
692        if value.signed {
693            json["signed"] = 1.into();
694        }
695        json
696    }
697}
698
699#[derive(Debug)]
700pub struct Module {
701    pub attributes: Metadata,
702    pub parameter_default_values: Metadata,
703    pub ports: Map<PortDetails>,
704    pub cells: Map<CellDetails>,
705    pub memories: Map<MemoryDetails>,
706    pub netnames: Map<NetDetails>,
707}
708
709impl Module {
710    pub fn new() -> Module {
711        Module {
712            attributes: Metadata::new(),
713            parameter_default_values: Metadata::new(),
714            ports: Map::new(),
715            cells: Map::new(),
716            memories: Map::new(),
717            netnames: Map::new(),
718        }
719    }
720}
721
722impl TryFrom<JsonValue> for Module {
723    type Error = SyntaxError;
724
725    fn try_from(mut value: JsonValue) -> Result<Self, Self::Error> {
726        let attributes = Metadata::try_from(value["attributes"].take())?;
727        let parameter_default_values = if value.has_key("parameter_default_values") {
728            Metadata::try_from(value["parameter_default_values"].take())?
729        } else {
730            Metadata::new()
731        };
732        let ports = Map::<PortDetails>::try_from(value["ports"].take())?;
733        let cells = Map::<CellDetails>::try_from(value["cells"].take())?;
734        let memories = if value.has_key("memories") {
735            Map::<MemoryDetails>::try_from(value["memories"].take())?
736        } else {
737            Map::new()
738        };
739        let netnames = Map::<NetDetails>::try_from(value["netnames"].take())?;
740        Ok(Module { attributes, parameter_default_values, ports, cells, memories, netnames })
741    }
742}
743
744impl From<Module> for JsonValue {
745    fn from(value: Module) -> JsonValue {
746        object! {
747            attributes: value.attributes,
748            parameter_default_values: value.parameter_default_values,
749            ports: value.ports,
750            cells: value.cells,
751            memories: value.memories,
752            netnames: value.netnames,
753        }
754    }
755}
756
757// One Yosys design corresponds to many prjunnamed designs.
758#[derive(Debug)]
759pub struct Design {
760    pub creator: String,
761    pub modules: Map<Module>,
762    // we don't care about AIG models
763}
764
765impl TryFrom<JsonValue> for Design {
766    type Error = SyntaxError;
767
768    fn try_from(mut value: JsonValue) -> Result<Self, Self::Error> {
769        let creator = value["creator"].as_str().map(|s| s.to_owned()).ok_or(SyntaxError(value["creator"].take()))?;
770        let modules = Map::<Module>::try_from(value["modules"].take())?;
771        Ok(Design { creator, modules })
772    }
773}
774
775impl From<Design> for JsonValue {
776    fn from(value: Design) -> JsonValue {
777        object! {
778            creator: value.creator,
779            modules: value.modules,
780        }
781    }
782}