1use prjunnamed_memory::{MemoryExt, MemorySwizzle};
2use prjunnamed_netlist::{
3 Cell, Const, ControlNet, Design, Memory, MemoryPortRelation, Net, Target, TargetCell, Trit, Value,
4};
5
6use crate::SiliconBlueTarget;
7
8#[derive(Clone, Debug)]
9struct BramLowering {
10 read_port_swizzles: Vec<MemorySwizzle>,
11}
12
13const OPT_FOR_AREA: bool = false;
14
15impl SiliconBlueTarget {
16 fn find_bram_lowering(&self, memory: &Memory) -> Option<BramLowering> {
17 if memory.write_ports.len() > 1 {
22 return None;
23 }
24 if memory.read_ports.iter().any(|port| port.flip_flop.is_none()) {
25 return None;
26 }
27 let write_port = memory.write_ports.get(0);
28 let mut read_port_swizzles = vec![];
29 for (read_port_index, read_port) in memory.read_ports.iter().enumerate() {
30 let mut cand_swizzles = vec![];
31 for base_mode in 0..3 {
32 if base_mode != 0 && !self.is_ice40() {
33 continue;
34 }
35 let mut soft_addr_bits_mask = 0;
36 let mut write_wide_log2 = vec![];
37 let data_swizzle = if let Some(write_port) = write_port {
38 let wide_log2 = write_port.wide_log2(memory);
39 if wide_log2 > base_mode {
40 for bit in base_mode..wide_log2 {
41 soft_addr_bits_mask |= 1 << bit;
42 }
43 }
44 let actual_wide_log2 = wide_log2.min(base_mode);
45 write_wide_log2.push(actual_wide_log2);
46 memory.make_data_swizzle(&[if base_mode == actual_wide_log2 {
47 1
48 } else {
49 16 >> base_mode << actual_wide_log2
50 }])
51 } else {
52 memory.make_data_swizzle(&[])
53 };
54 let read_wide_log2 = read_port.wide_log2(memory);
55 if read_wide_log2 > base_mode {
56 for bit in base_mode..read_wide_log2 {
57 soft_addr_bits_mask |= 1 << bit;
58 }
59 }
60 let read_wide_log2 = vec![read_wide_log2.min(base_mode)];
61 let mut swizzle = MemorySwizzle {
62 data_swizzle,
63 soft_addr_bits_mask,
64 write_wide_log2,
65 read_wide_log2,
66 hard_addr_bits: 8 + base_mode,
67 data_width_unit: 16 >> base_mode,
68 };
69 cand_swizzles.push(swizzle.clone());
70 if write_port.is_some() && swizzle.write_wide_log2[0] != base_mode {
71 swizzle.write_wide_log2[0] = base_mode;
72 swizzle.data_swizzle = memory.make_data_swizzle(&[1]);
73 cand_swizzles.push(swizzle);
74 }
75 }
76 let best_swizzle = if OPT_FOR_AREA {
77 cand_swizzles
78 .into_iter()
79 .min_by_key(|swizzle| {
80 let num_brams = memory.swizzle_depths(swizzle).len();
81 let (write_mux_bits, read_mux_bits) = memory.swizzle_mux_bits(&[read_port_index], swizzle);
82 let write_mux_bits = write_mux_bits.get(0).copied().unwrap_or(0);
83 let read_mux_bits = read_mux_bits[0];
84 (num_brams, read_mux_bits, write_mux_bits)
85 })
86 .unwrap()
87 } else {
88 cand_swizzles
89 .into_iter()
90 .min_by_key(|swizzle| {
91 let num_brams = memory.swizzle_depths(swizzle).len();
92 let (write_mux_bits, read_mux_bits) = memory.swizzle_mux_bits(&[read_port_index], swizzle);
93 let write_mux_bits = write_mux_bits.get(0).copied().unwrap_or(0);
94 let read_mux_bits = read_mux_bits[0];
95 (read_mux_bits, num_brams, write_mux_bits)
96 })
97 .unwrap()
98 };
99 read_port_swizzles.push(best_swizzle);
100 }
101 Some(BramLowering { read_port_swizzles })
102 }
103
104 fn swizzle_bram_addr(&self, port_width: usize, addr: &Value) -> Value {
105 assert!(addr.len() >= 8 && addr.len() <= 11);
106 assert_eq!(port_width, 16 >> (addr.len() - 8));
107 match addr.len() {
108 8 => addr.zext(11),
109 9 => addr.slice(1..).concat(addr[0]).zext(11),
110 10 => addr.slice(2..).concat(addr[1]).concat(addr[0]).zext(11),
111 11 => addr.slice(3..).concat(addr[2]).concat(addr[1]).concat(addr[0]),
112 _ => unreachable!(),
113 }
114 }
115
116 fn lower_single_bram(&self, design: &Design, memory: &Memory, output: &Value) {
117 const SWIZZLE16: [usize; 16] = [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15];
118 let prototype = self.prototype("SB_RAM40_4K").unwrap();
119 let mut target_cell = TargetCell::new("SB_RAM40_4K", prototype);
120
121 assert!(memory.write_ports.len() <= 1);
122 assert_eq!(memory.read_ports.len(), 1);
123 assert!(memory.depth * memory.width <= 0x1000);
124
125 if let Some(write_port) = memory.write_ports.get(0) {
126 prototype.apply_param(&mut target_cell, "IS_WCLK_INVERTED", write_port.clock.is_negative());
127 prototype.apply_input(&mut target_cell, "WCLK", write_port.clock.net());
128 prototype.apply_input(&mut target_cell, "WE", Net::ONE);
129 prototype.apply_input(
130 &mut target_cell,
131 "WADDR",
132 self.swizzle_bram_addr(write_port.data.len(), &write_port.addr),
133 );
134 prototype.apply_param(&mut target_cell, "WRITE_MODE", (write_port.addr.len() - 8) as i64);
135 if write_port.data.len() != 16 {
136 prototype.apply_input(&mut target_cell, "WCLKE", write_port.mask[0]);
137 for bit in &write_port.mask {
138 if bit != Net::UNDEF {
139 assert_eq!(bit, write_port.mask[0]);
140 }
141 }
142 } else {
143 prototype.apply_input(&mut target_cell, "WCLKE", Net::ONE);
144 }
145 match write_port.data.len() {
146 16 => {
147 prototype.apply_input(
148 &mut target_cell,
149 "WDATA",
150 Value::from_iter(SWIZZLE16.into_iter().map(|index| write_port.data[index])),
151 );
152 prototype.apply_input(
153 &mut target_cell,
154 "MASK",
155 design.add_not(Value::from_iter(SWIZZLE16.into_iter().map(|index| write_port.mask[index]))),
156 );
157 }
158 8 => {
159 prototype.apply_input(
160 &mut target_cell,
161 "WDATA",
162 Value::from_iter(SWIZZLE16.into_iter().map(|index| {
163 if index < 8 {
164 write_port.data[index]
165 } else {
166 Net::UNDEF
167 }
168 })),
169 );
170 }
171 4 => {
172 prototype.apply_input(
173 &mut target_cell,
174 "WDATA",
175 Value::from_iter(SWIZZLE16.into_iter().map(|index| {
176 if index >= 8 && index < 12 {
177 write_port.data[index - 8]
178 } else {
179 Net::UNDEF
180 }
181 })),
182 );
183 }
184 2 => {
185 prototype.apply_input(
186 &mut target_cell,
187 "WDATA",
188 Value::from_iter(SWIZZLE16.into_iter().map(|index| {
189 if index >= 12 && index < 14 {
190 write_port.data[index - 12]
191 } else {
192 Net::UNDEF
193 }
194 })),
195 );
196 }
197 _ => unreachable!(),
198 }
199 } else {
200 prototype.apply_input(&mut target_cell, "WCLK", Net::ZERO);
201 }
202
203 let read_port = &memory.read_ports[0];
204 let read_ff = read_port.flip_flop.as_ref().unwrap();
205 prototype.apply_param(&mut target_cell, "IS_RCLK_INVERTED", read_ff.clock.is_negative());
206 prototype.apply_input(&mut target_cell, "RCLK", read_ff.clock.net());
207 assert!(read_ff.enable.is_positive());
208 prototype.apply_input(&mut target_cell, "RCLKE", read_ff.enable.net());
209 prototype.apply_input(&mut target_cell, "RE", Net::ONE);
210 assert!(!read_ff.has_reset());
211 assert!(!read_ff.has_clear());
212 assert!(!read_ff.has_init_value());
213 for &relation in &read_ff.relations {
214 assert_eq!(relation, MemoryPortRelation::Undefined);
215 }
216 prototype.apply_input(&mut target_cell, "RADDR", self.swizzle_bram_addr(read_port.data_len, &read_port.addr));
217 prototype.apply_param(&mut target_cell, "READ_MODE", (read_port.addr.len() - 8) as i64);
218
219 let init_value = Const::from_iter((0..0x1000).map(|index| {
220 let swz_index = (index & 0xff0) | SWIZZLE16[index & 0xf];
221 if swz_index < memory.init_value.len() {
222 memory.init_value[swz_index]
223 } else {
224 Trit::Undef
225 }
226 }));
227 prototype.apply_param(&mut target_cell, "INIT", init_value);
228
229 let target_cell_output = design.add_target(target_cell);
230 let rdata = prototype.extract_output(&target_cell_output, "RDATA");
231 match memory.read_ports[0].data_len {
232 16 => {
233 for (rdata_bit, index) in SWIZZLE16.into_iter().enumerate() {
234 design.replace_net(output[index], rdata[rdata_bit]);
235 }
236 }
237 8 => {
238 for (rdata_bit, index) in SWIZZLE16.into_iter().enumerate() {
239 if index < 8 {
240 design.replace_net(output[index], rdata[rdata_bit]);
241 }
242 }
243 }
244 4 => {
245 for (rdata_bit, index) in SWIZZLE16.into_iter().enumerate() {
246 if index >= 8 && index < 12 {
247 design.replace_net(output[index - 8], rdata[rdata_bit]);
248 }
249 }
250 }
251 2 => {
252 for (rdata_bit, index) in SWIZZLE16.into_iter().enumerate() {
253 if index >= 12 && index < 14 {
254 design.replace_net(output[index - 12], rdata[rdata_bit]);
255 }
256 }
257 }
258 _ => unreachable!(),
259 }
260 }
261
262 fn lower_to_bram(&self, design: &Design, memory: &Memory, output: &Value, lowering: BramLowering) {
263 for (read_port_index, swizzle) in lowering.read_port_swizzles.iter().enumerate() {
264 let (mut port_memory, mut port_output) = memory.extract_read_ports(&[read_port_index], output);
265 port_memory.unmap_read_init_reset_transparency(design, 0, true, &mut port_output);
266 let read_ff = port_memory.read_ports[0].flip_flop.as_mut().unwrap();
267 if let ControlNet::Neg(en) = read_ff.enable {
268 read_ff.enable = ControlNet::Pos(design.add_not1(en));
269 }
270 port_memory.emulate_read_before_write(design);
271 for (final_memory, final_output) in port_memory.swizzle(design, &port_output, swizzle) {
272 self.lower_single_bram(design, &final_memory, &final_output);
273 }
274 }
275 }
276
277 pub fn lower_memories(&self, design: &mut Design) {
278 for cell_ref in design.iter_cells() {
279 let Cell::Memory(memory) = &*cell_ref.get() else { continue };
280 let _guard = design.use_metadata_from(&[cell_ref]);
281 let output = cell_ref.output();
282 let bram_lowering = self.find_bram_lowering(memory);
283 let fallback_ok = memory.can_lower_fallback();
284 let fallback_reasonable =
285 fallback_ok && if memory.write_ports.len() != 0 { memory.depth <= 1 } else { memory.depth <= 5 };
286 cell_ref.unalive();
287 if bram_lowering.is_some() && !fallback_reasonable {
288 self.lower_to_bram(design, memory, &output, bram_lowering.unwrap());
289 } else {
290 memory.clone().lower_fallback(design, &output);
291 }
292 }
293 design.compact();
294 }
295}