calyx_ir/
utils.rs

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
//! Helpers used to examine calyx programs. Used in Xilinx and Yxi backends among others.
use super::{BoolAttr, Cell, Component, RRC};
use calyx_utils::Id;
#[cfg(feature = "serialize")]
use serde::Serialize;

// Returns Vec<String> of `@external` or `ref` memory names
pub fn external_and_ref_memories_names(comp: &Component) -> Vec<String> {
    external_and_ref_memories_cells(comp)
        .iter()
        .map(|cell_ref| cell_ref.borrow().name().to_string())
        .collect()
}

/// Gets all memory cells in top level marked `@external` or `ref`.
pub fn external_and_ref_memories_cells(comp: &Component) -> Vec<RRC<Cell>> {
    comp.cells
        .iter()
        // find external and ref memories
        .filter(|cell_ref| {
            let cell = cell_ref.borrow();
            cell.attributes.has(BoolAttr::External) || cell.is_reference()
        })
        .cloned()
        .collect()
}

#[cfg_attr(feature = "serialize", derive(Serialize))]
#[derive(Clone, Copy)]
pub enum MemoryType {
    Combinational,
    Sequential,
    Dynamic,
}

/// Parameters for std memories
pub struct MemInfo {
    pub name: String,
    pub memory_type: MemoryType,
    pub data_width: u64,
    pub dimensions: u64,
    //dimension sizes in order: d1, d2, etc.
    pub dimension_sizes: Vec<u64>,
    pub total_size: u64,
    //idx port width, in case size is ambiguous
    pub idx_sizes: Vec<u64>,
}

// Returns a vector of tuples containing memory info of [comp] of form:
// [(WIDTH, SIZE, IDX_SIZE)]
pub trait GetMemInfo {
    fn get_mem_info(&self) -> Vec<MemInfo>;
}

impl GetMemInfo for Vec<RRC<Cell>> {
    fn get_mem_info(&self) -> Vec<MemInfo> {
        //Params of dimensions for multi dimensional memories. d1 memories use `"SIZE"`.
        let dimension_params = ["D0_SIZE", "D1_SIZE", "D2_SIZE", "D3_SIZE"];
        self.iter()
              .map(|cr| {
                  let mem = cr.borrow();
                  let mut dimension_sizes: Vec<u64> = Vec::new();
                  let mut idx_sizes: Vec<u64> = Vec::new();
                  let mem_cell_type = mem.prototype.get_name().unwrap(); //i.e. "comb_mem_d1"
                  let mem_type : MemoryType = if mem_cell_type.to_string().contains("comb") {
                      MemoryType::Combinational
                    } else if mem_cell_type.to_string().contains("seq") {
                        MemoryType::Sequential
                    } else {
                        MemoryType::Dynamic
                    };

                    let dimensions = dimension_count(mem_cell_type);
                    if dimensions == 1{
                        dimension_sizes.push(mem.get_parameter("SIZE").unwrap());
                        idx_sizes.push(mem.get_parameter("IDX_SIZE").unwrap());
                    }
                    else if dimensions > 1 && dimensions <= 4{
                        for i in 0..dimensions {
                            dimension_sizes.push(mem.get_parameter(dimension_params[i as usize]).unwrap());
                            idx_sizes.push(mem.get_parameter(format!("D{}_IDX_SIZE",i)).unwrap());
                        }
                    }
                    else{
                            unreachable!("It is not expected for memory primitives to have more than 4 dimensions.");
                    };
                  let total_size = dimension_sizes.clone().iter().product();
                  MemInfo {
                      name: mem.name().to_string(),
                      memory_type: mem_type,
                      data_width: mem.get_parameter("WIDTH").unwrap(),
                      dimensions,
                      dimension_sizes,
                      total_size,
                      idx_sizes
                  }
              })
              .collect()
    }
}

impl GetMemInfo for Component {
    fn get_mem_info(&self) -> Vec<MemInfo> {
        external_and_ref_memories_cells(self).get_mem_info()
    }
}

fn dimension_count(mem_id: Id) -> u64 {
    let mem_name = mem_id.as_ref();

    if mem_name.contains("d1") {
        1
    } else if mem_name.contains("d2") {
        2
    } else if mem_name.contains("d3") {
        3
    } else if mem_name.contains("d4") {
        4
    } else {
        panic!(
            "Cell {} does not seem to be a memory primitive. Memory primitives are expected to have 1-4 dimensions inclusive.",
            mem_name
        );
    }
}