calyx_ir/
utils.rs

1//! Helpers used to examine calyx programs. Used in Xilinx and Yxi backends among others.
2use super::{BoolAttr, Cell, Component, RRC};
3use calyx_utils::Id;
4#[cfg(feature = "serialize")]
5use serde::Serialize;
6
7// Returns Vec<String> of `@external` or `ref` memory names
8pub fn external_and_ref_memories_names(comp: &Component) -> Vec<String> {
9    external_and_ref_memories_cells(comp)
10        .iter()
11        .map(|cell_ref| cell_ref.borrow().name().to_string())
12        .collect()
13}
14
15/// Gets all memory cells in top level marked `@external` or `ref`.
16pub fn external_and_ref_memories_cells(comp: &Component) -> Vec<RRC<Cell>> {
17    comp.cells
18        .iter()
19        // find external and ref memories
20        .filter(|cell_ref| {
21            let cell = cell_ref.borrow();
22            cell.attributes.has(BoolAttr::External) || cell.is_reference()
23        })
24        .cloned()
25        .collect()
26}
27
28#[cfg_attr(feature = "serialize", derive(Serialize))]
29#[derive(Clone, Copy)]
30pub enum MemoryType {
31    Combinational,
32    Sequential,
33    Dynamic,
34}
35
36/// Parameters for std memories
37pub struct MemInfo {
38    pub name: String,
39    pub memory_type: MemoryType,
40    pub data_width: u64,
41    pub dimensions: u64,
42    //dimension sizes in order: d1, d2, etc.
43    pub dimension_sizes: Vec<u64>,
44    pub total_size: u64,
45    //idx port width, in case size is ambiguous
46    pub idx_sizes: Vec<u64>,
47}
48
49// Returns a vector of tuples containing memory info of [comp] of form:
50// [(WIDTH, SIZE, IDX_SIZE)]
51pub trait GetMemInfo {
52    fn get_mem_info(&self) -> Vec<MemInfo>;
53}
54
55impl GetMemInfo for Vec<RRC<Cell>> {
56    fn get_mem_info(&self) -> Vec<MemInfo> {
57        //Params of dimensions for multi dimensional memories. d1 memories use `"SIZE"`.
58        let dimension_params = ["D0_SIZE", "D1_SIZE", "D2_SIZE", "D3_SIZE"];
59        self.iter()
60              .map(|cr| {
61                  let mem = cr.borrow();
62                  let mut dimension_sizes: Vec<u64> = Vec::new();
63                  let mut idx_sizes: Vec<u64> = Vec::new();
64                  let mem_cell_type = mem.prototype.get_name().unwrap(); //i.e. "comb_mem_d1"
65                  let mem_type : MemoryType = if mem_cell_type.to_string().contains("comb") {
66                      MemoryType::Combinational
67                    } else if mem_cell_type.to_string().contains("seq") {
68                        MemoryType::Sequential
69                    } else {
70                        MemoryType::Dynamic
71                    };
72
73                    let dimensions = dimension_count(mem_cell_type);
74                    if dimensions == 1{
75                        dimension_sizes.push(mem.get_parameter("SIZE").unwrap());
76                        idx_sizes.push(mem.get_parameter("IDX_SIZE").unwrap());
77                    }
78                    else if dimensions > 1 && dimensions <= 4{
79                        for i in 0..dimensions {
80                            dimension_sizes.push(mem.get_parameter(dimension_params[i as usize]).unwrap());
81                            idx_sizes.push(mem.get_parameter(format!("D{i}_IDX_SIZE")).unwrap());
82                        }
83                    }
84                    else{
85                            unreachable!("It is not expected for memory primitives to have more than 4 dimensions.");
86                    };
87                  let total_size = dimension_sizes.clone().iter().product();
88                  MemInfo {
89                      name: mem.name().to_string(),
90                      memory_type: mem_type,
91                      data_width: mem.get_parameter("WIDTH").unwrap(),
92                      dimensions,
93                      dimension_sizes,
94                      total_size,
95                      idx_sizes
96                  }
97              })
98              .collect()
99    }
100}
101
102impl GetMemInfo for Component {
103    fn get_mem_info(&self) -> Vec<MemInfo> {
104        external_and_ref_memories_cells(self).get_mem_info()
105    }
106}
107
108fn dimension_count(mem_id: Id) -> u64 {
109    let mem_name = mem_id.as_ref();
110
111    if mem_name.contains("d1") {
112        1
113    } else if mem_name.contains("d2") {
114        2
115    } else if mem_name.contains("d3") {
116        3
117    } else if mem_name.contains("d4") {
118        4
119    } else {
120        panic!(
121            "Cell {mem_name} does not seem to be a memory primitive. Memory primitives are expected to have 1-4 dimensions inclusive."
122        );
123    }
124}