logicaffeine_compile/codegen_ana/
place.rs1use super::cell::{ASrc, AnalogCell, AnalogNetlist};
11use super::target::{AnaUnplaceable, AnalogTarget};
12use super::AnaLowerError;
13
14#[derive(Clone, Debug, PartialEq)]
16pub struct AnalogPlacement {
17 pub site: Vec<(usize, usize)>,
18}
19
20impl AnalogPlacement {
21 pub fn pitch_distance(&self, a: usize, b: usize) -> f64 {
23 let (ar, ac) = self.site[a];
24 let (br, bc) = self.site[b];
25 (ar.abs_diff(br) + ac.abs_diff(bc)) as f64
26 }
27
28 pub fn wire_cost(&self, netlist: &AnalogNetlist) -> f64 {
30 let mut cost = 0.0;
31 for (i, cell) in netlist.cells.iter().enumerate() {
32 let mut add = |s: &ASrc| {
33 if let ASrc::Val(v) = s {
34 cost += self.pitch_distance(i, *v);
35 }
36 };
37 match cell {
38 AnalogCell::Sum { inputs, .. } => inputs.iter().for_each(&mut add),
39 AnalogCell::Mul { a, b } => {
40 add(a);
41 add(b);
42 }
43 AnalogCell::GainConst { a, .. } => add(a),
44 AnalogCell::Select { c, t, f } => {
45 add(c);
46 add(t);
47 add(f);
48 }
49 AnalogCell::Exp { a }
50 | AnalogCell::Log { a }
51 | AnalogCell::Tanh { a }
52 | AnalogCell::Sqrt { a } => add(a),
53 AnalogCell::Div { a, b } => {
54 add(a);
55 add(b);
56 }
57 }
58 }
59 cost
60 }
61}
62
63pub fn place_analog(
67 netlist: &AnalogNetlist,
68 target: &AnalogTarget,
69) -> Result<AnalogPlacement, AnaLowerError> {
70 let sites_total = target.rows * target.cols;
71 if netlist.cells.len() > sites_total {
72 return Err(AnaLowerError::Unplaceable(AnaUnplaceable::TooSmall {
73 needed_cells: netlist.cells.len(),
74 target_rows: target.rows,
75 target_cols: target.cols,
76 target: target.name,
77 }));
78 }
79 let mut used = vec![false; sites_total];
80 let mut site: Vec<(usize, usize)> = Vec::with_capacity(netlist.cells.len());
81 for (i, cell) in netlist.cells.iter().enumerate() {
82 let operands: Vec<usize> = operand_cells(cell);
83 let mut best: Option<(f64, usize)> = None;
84 for s in 0..sites_total {
85 if used[s] {
86 continue;
87 }
88 let (r, c) = (s / target.cols, s % target.cols);
89 let d: f64 = operands
90 .iter()
91 .map(|o| {
92 let (or, oc) = site[*o];
93 (r.abs_diff(or) + c.abs_diff(oc)) as f64
94 })
95 .sum();
96 if best.map(|(bd, _)| d < bd).unwrap_or(true) {
97 best = Some((d, s));
98 }
99 }
100 let (_, s) = best.expect("a free site exists (counted above)");
101 used[s] = true;
102 site.push((s / target.cols, s % target.cols));
103 let _ = i;
104 }
105 Ok(AnalogPlacement { site })
106}
107
108pub fn place_blind(
111 netlist: &AnalogNetlist,
112 target: &AnalogTarget,
113) -> Result<AnalogPlacement, AnaLowerError> {
114 let sites_total = target.rows * target.cols;
115 if netlist.cells.len() > sites_total {
116 return Err(AnaLowerError::Unplaceable(AnaUnplaceable::TooSmall {
117 needed_cells: netlist.cells.len(),
118 target_rows: target.rows,
119 target_cols: target.cols,
120 target: target.name,
121 }));
122 }
123 let stride = (sites_total / 2).max(1) | 1;
125 let mut used = vec![false; sites_total];
126 let mut cursor = 0usize;
127 let mut site = Vec::with_capacity(netlist.cells.len());
128 for _ in &netlist.cells {
129 while used[cursor] {
130 cursor = (cursor + 1) % sites_total;
131 }
132 used[cursor] = true;
133 site.push((cursor / target.cols, cursor % target.cols));
134 cursor = (cursor + stride) % sites_total;
135 }
136 Ok(AnalogPlacement { site })
137}
138
139fn operand_cells(cell: &AnalogCell) -> Vec<usize> {
140 let mut out = Vec::new();
141 let mut add = |s: &ASrc| {
142 if let ASrc::Val(v) = s {
143 out.push(*v);
144 }
145 };
146 match cell {
147 AnalogCell::Sum { inputs, .. } => inputs.iter().for_each(&mut add),
148 AnalogCell::Mul { a, b } => {
149 add(a);
150 add(b);
151 }
152 AnalogCell::GainConst { a, .. } => add(a),
153 AnalogCell::Select { c, t, f } => {
154 add(c);
155 add(t);
156 add(f);
157 }
158 AnalogCell::Exp { a }
159 | AnalogCell::Log { a }
160 | AnalogCell::Tanh { a }
161 | AnalogCell::Sqrt { a } => add(a),
162 AnalogCell::Div { a, b } => {
163 add(a);
164 add(b);
165 }
166 }
167 out
168}