gaffe_xilinx/xc7/
configuration.rs

1use ::failure::Error;
2use ::std::collections::BTreeMap;
3use ::std::fmt;
4use super::Bitstream;
5use super::DeviceDefinition;
6use super::FrameAddress;
7use super::FromWord;
8use super::Opcode;
9use super::Packet;
10use super::RegisterAddress;
11use super::Word;
12use super::frame_address::BlockType;
13use super::frame_address::DeviceHalf;
14use super::registers;
15
16pub struct Frame([Word; 101]);
17
18impl fmt::Debug for Frame {
19    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
20        writeln!(f, "")?;
21        for (row, payload_line) in self.0.chunks(4).enumerate() {
22            write!(f, "{:04x}:    ", row * 4)?;
23            for (col, payload_word) in payload_line.iter().enumerate() {
24                write!(f, "{:08x}{}", payload_word,
25                    match col+1 {
26                        n if n == payload_line.len() => "",
27                        _ => " ",
28                    }
29                )?;
30            }
31            writeln!(f, "")?;
32        }
33        Ok(())
34    }
35}
36
37#[derive(Debug)]
38pub struct Configuration {
39    device: DeviceDefinition,
40    frames: BTreeMap<FrameAddress, Frame>,
41}
42
43impl Configuration {
44    pub fn from_bitstream_for_device(bitstream: &Bitstream, device_def: &DeviceDefinition) -> Result<Self, Error>
45    {
46        let mut cmd_reg = registers::CommandRegister::default();
47        let mut far_reg = registers::FrameAddressRegister::default();
48        let mut mask_reg = registers::MaskRegister::default();
49        let mut ctl1_reg = registers::ControlRegister1::default();
50
51        let mut next_frame_write_address = FrameAddress::default();
52        let mut last_register_address = RegisterAddress::default();
53        let mut load_far_on_next_fdri = false;
54        let mut idcode_matched = false;
55        let mut config_frames = BTreeMap::<FrameAddress, Frame>::new();
56        for packet in bitstream.iter() {
57            match packet {
58                Packet::Type1{
59                    opcode: _,
60                    address,
61                    payload: _,
62                } => last_register_address = *address,
63                _ => (),
64            }
65
66            match packet {
67                Packet::Type1{
68                    opcode: Opcode::Write,
69                    address: RegisterAddress::IDCODE,
70                    payload,
71                } => {
72                    let idcode = registers::IdCodeRegister::from_word(payload[0])?;
73                    idcode_matched = idcode == device_def.idcode;
74                    if !idcode_matched {
75                        return Err(format_err!("Bitstream has wrong IDCODE expected={:x} actual={:x}", device_def.idcode, idcode));
76                    }
77                },
78                Packet::Type1{
79                    opcode: Opcode::Write,
80                    address: RegisterAddress::CTL1,
81                    payload,
82                } => {
83                    ctl1_reg = registers::ControlRegister1::from_word(payload[0] & mask_reg.value)?
84                },
85                Packet::Type1{
86                    opcode: Opcode::Write,
87                    address: RegisterAddress::MASK,
88                    payload,
89                } => {
90                    mask_reg = registers::MaskRegister::from_word(payload[0])?;
91                    },
92                Packet::Type1{
93                    opcode: Opcode::Write,
94                    address: RegisterAddress::CMD,
95                    payload,
96                } => {
97                    cmd_reg = registers::CommandRegister::from_word(payload[0])?;
98                    if cmd_reg.command == registers::Command::WriteConfigData {
99                        load_far_on_next_fdri = true;
100                    }
101                },
102                Packet::Type1{
103                    opcode: Opcode::Write,
104                    address: RegisterAddress::FAR,
105                    payload,
106                } => {
107                    far_reg = registers::FrameAddressRegister::from_word(payload[0])?;
108
109                    // Per UG470, the last command written to CMD is re-executed
110                    // each time FAR is written. In PERFRAMECRC bitstreams, FAR
111                    // is loaded once to start the write and then each frame is
112                    // sent individually to FDRI. FAR is also written after each
113                    // FDRI to mark progress. These latter writes to FAR do not
114                    // appear to alter the auto-incremented frame address. This
115                    // difference in behavior seems to be controlled by an
116                    // undocumented bit in CTRL1 that inhibits CMD re-execution
117                    // during writes to FAR.
118                    if !ctl1_reg.inhibit_cmd_reexec_on_far_write && cmd_reg.command == registers::Command::WriteConfigData {
119                        load_far_on_next_fdri = true;
120                    }
121                },
122                Packet::Type1{
123                    opcode: Opcode::Write,
124                    address: RegisterAddress::FDRI,
125                    payload,
126                } if idcode_matched => {
127                    if load_far_on_next_fdri {
128                        next_frame_write_address = far_reg;
129                        load_far_on_next_fdri = false;
130                    }
131
132                    let mut frame_address_iter = device_def.config_mem_layout.iter();
133                    let mut frame_address_iter = frame_address_iter.skip_past(&next_frame_write_address);
134
135                    let mut frame_chunk_iter = payload.chunks(101);
136                    loop {
137                        let current_address = next_frame_write_address;
138
139                        let frame_chunk = match frame_chunk_iter.next() {
140                            Some(x) => x,
141                            None => break
142                        };
143
144                        let mut frame_words = [0u32; 101];
145                        frame_words.copy_from_slice(frame_chunk);
146                        config_frames.insert(current_address, Frame(frame_words));
147                        debug!("Wrote {:p}", current_address);
148
149                        next_frame_write_address = match frame_address_iter.next() {
150                            Some(x) if !current_address.in_same_row(&x) => {
151                                debug!("Skipping row switch padding");
152                                frame_chunk_iter.next();
153                                frame_chunk_iter.next();
154                                x
155                            },
156                            Some(x) => x,
157                            None => {
158                                debug!("Skipping row switch padding at end of config mem");
159                                frame_chunk_iter.next();
160                                frame_chunk_iter.next();
161                                current_address
162                            },
163                        };
164                    }
165                },
166                Packet::Type2{
167                    opcode: Opcode::Write,
168                    payload,
169                } if idcode_matched && last_register_address == RegisterAddress::FDRI => {
170                    if load_far_on_next_fdri {
171                        next_frame_write_address = far_reg;
172                        load_far_on_next_fdri = false;
173                    }
174
175                    let mut frame_address_iter = device_def.config_mem_layout.iter();
176                    let mut frame_address_iter = frame_address_iter.skip_past(&next_frame_write_address);
177
178                    let mut frame_chunk_iter = payload.chunks(101);
179                    loop {
180                        let current_address = next_frame_write_address;
181
182                        let frame_chunk = match frame_chunk_iter.next() {
183                            Some(x) => x,
184                            None => break
185                        };
186
187                        let mut frame_words = [0u32; 101];
188                        frame_words.copy_from_slice(frame_chunk);
189                        config_frames.insert(current_address, Frame(frame_words));
190
191                        next_frame_write_address = match frame_address_iter.next() {
192                            Some(x) if !current_address.in_same_row(&x) => {
193                                debug!("Skipping row switch padding");
194                                frame_chunk_iter.next();
195                                frame_chunk_iter.next();
196                                x
197                            },
198                            Some(x) => x,
199                            None => {
200                                debug!("Skipping row switch padding at end of config mem");
201                                frame_chunk_iter.next();
202                                frame_chunk_iter.next();
203                                current_address
204                            },
205                        };
206                    }
207
208                    next_frame_write_address = frame_address_iter.next().unwrap_or_default();
209                },
210                Packet::Type1{
211                    opcode: Opcode::Write,
212                    address: RegisterAddress::LOUT,
213                    payload,
214                } => {
215                    debug!("LOUT {:p}", FrameAddress::from_word(payload[0])?);
216                },
217                _ => continue,
218            }
219        }
220
221        Ok(Configuration{
222            device: device_def.clone(),
223            frames: config_frames,
224        })
225    }
226}
227
228impl Into<Bitstream> for Configuration {
229    fn into(self) -> Bitstream {
230        let mut packets = Vec::new();
231
232        packets.push(Packet::nop());
233
234        packets.push(Packet::from(registers::WatchdogTimerRegister{
235            timer_user_mon: false,
236            timer_cfg_mon: false,
237            timer_val: 0.into(),
238        }));
239        packets.push(Packet::from(registers::WarmBootStartAddressRegister{
240            rs: 0.into(),
241            rs_ts_b: false,
242            start_addr: 0.into(),
243        }));
244        packets.push(Packet::from(registers::CommandRegister{
245            command: registers::Command::Null,
246        }));
247        packets.push(Packet::nop());
248
249        packets.push(Packet::from(registers::CommandRegister{
250            command: registers::Command::ResetCrc,
251        }));
252        packets.push(Packet::nop());
253        packets.push(Packet::nop());
254
255        packets.push(Packet::from(registers::ConfigurationOptionsRegister0{
256            pwrdwn_stat: false,
257            done_pipe: true,
258            drive_done: false,
259            single: false,
260            oscfsel: 0.into(),
261            ssclksrc_jtag: false,
262            ssclksrc_user: false,
263            done_cycle: registers::StartupPhaseKeep::Phase3,
264            match_cycle: registers::StartupPhaseNoWait::NoWait,
265            lock_cycle: registers::StartupPhaseNoWait::NoWait,
266            gts_cycle: registers::StartupPhaseTracksDone::Phase5,
267            gwe_cycle: registers::StartupPhaseTracksDone::Phase6,
268        }));
269        packets.push(Packet::from(registers::ConfigurationOptionsRegister1{
270            persist_deassert_at_desync: false,
271            rb_crc_action: registers::RbCrcAction::Continue,
272            rb_crc_no_pin: false,
273            rb_crc_en: false,
274            bpi_first_read_cycle: 0.into(),
275            bpi_page_size: registers::BpiPageSize::OneBytePerWord,
276        }));
277        packets.push(Packet::from(self.device.idcode));
278        packets.push(Packet::from(registers::CommandRegister{
279            command: registers::Command::Switch,
280        }));
281        packets.push(Packet::nop());
282
283        packets.push(Packet::from(registers::MaskRegister{
284            value: 0x401,
285        }));
286        packets.push(Packet::from(registers::ControlRegister0{
287            efuse_key: false,
288            icap_select:false,
289            over_temp_power_down: false,
290            config_fallback: true,
291            glutmask_b: true,
292            farsrc: false,
293            dec: false,
294            writes_disabled: false,
295            reads_disabled: false,
296            persist: false,
297            gts_usr_b: true,
298        }));
299        packets.push(Packet::from(registers::MaskRegister{
300            value: 0x0,
301        }));
302        packets.push(Packet::from(registers::ControlRegister1{
303            inhibit_cmd_reexec_on_far_write: false,
304        }));
305        packets.append(&mut vec![Packet::nop(); 8]);
306
307        // Frames can be grouped into a single write where the address is
308        // autoincremented for each frame. Doing so requires that there are no
309        // gaps in the frame addresses we wish to write.
310        let mut frame_address_iter = None;
311        let mut fdri_payload = Vec::<Word>::new();
312        let mut last_address: Option<FrameAddress> = None;
313        for (addr, frame) in self.frames.iter() {
314            frame_address_iter = match frame_address_iter {
315                None => {
316                    packets.push(Packet::from(*addr));
317                    packets.push(Packet::from(registers::CommandRegister{
318                        command: registers::Command::WriteConfigData,
319                    }));
320                    packets.push(Packet::nop());
321
322                    Some(self.device.config_mem_layout.iter().skip_past(addr))
323                },
324                Some(mut x) => {
325                    let next_addr_in_device = x.next().expect("Write past last address in device");
326
327                    // Was the last frame written the end of a row? `addr`
328                    // doesn't tell us as the frame data to be written may have
329                    // a gap. Instead, look at the next address in the device's
330                    // address space.
331                    match last_address {
332                        Some(x) if !x.in_same_row(&next_addr_in_device) => {
333                            // Include 2 frames of zero-filled padding at the end of a row.
334                            fdri_payload.extend_from_slice(&[0u32; 202]);
335                        },
336                        _ => (),
337                    }
338
339                    // If the next address to write is _not_ the next address in
340                    // the device, a new FDRI write needs to be started.
341                    if next_addr_in_device != *addr {
342                        // Small payloads can fit in a Type1 packet but larger
343                        // payloads need a combination of a zero-length Type1 to
344                        // set the register address and a Type2 to carry the
345                        // actual data.
346                        if fdri_payload.len() > 2048 {
347                            packets.push(Packet::Type1{
348                                opcode: Opcode::Write,
349                                address: RegisterAddress::FDRI,
350                                payload: fdri_payload,
351                            });
352                            fdri_payload = Vec::new();
353                        } else {
354                            packets.push(Packet::Type1{
355                                opcode: Opcode::Write,
356                                address: RegisterAddress::FDRI,
357                                payload: Vec::new(),
358                            });
359                            packets.push(Packet::Type2{
360                                opcode: Opcode::Write,
361                                payload: fdri_payload,
362                            });
363                            fdri_payload = Vec::new();
364                        }
365                        packets.push(Packet::from(*addr));
366                        packets.push(Packet::nop());
367
368                        Some(x.skip_past(addr))
369                    } else {
370                        Some(x)
371                    }
372                }
373            };
374            fdri_payload.extend_from_slice(&frame.0);
375            last_address = Some(*addr);
376        }
377
378        if let (Some(mut iter), Some(last)) = (frame_address_iter, last_address) {
379            match iter.next() {
380                Some(ref next) if last.in_same_row(next) => (),
381                _ => {
382                    // Include 2 frames of zero-filled padding at the end of a row.
383                    fdri_payload.extend_from_slice(&[0u32; 202]);
384                }
385            }
386
387        }
388
389        if !fdri_payload.is_empty() {
390            // Small payloads can fit in a Type1 packet but larger
391            // payloads need a combination of a zero-length Type1 to
392            // set the register address and a Type2 to carry the
393            // actual data.
394            if fdri_payload.len() < 2048 {
395                packets.push(Packet::Type1{
396                    opcode: Opcode::Write,
397                    address: RegisterAddress::FDRI,
398                    payload: fdri_payload,
399                });
400            } else {
401                packets.push(Packet::Type1{
402                    opcode: Opcode::Write,
403                    address: RegisterAddress::FDRI,
404                    payload: Vec::new(),
405                });
406                packets.push(Packet::Type2{
407                    opcode: Opcode::Write,
408                    payload: fdri_payload,
409                });
410            }
411        }
412
413        packets.push(Packet::nop());
414        packets.push(Packet::nop());
415
416        packets.push(Packet::from(registers::CommandRegister{
417            command: registers::Command::PulseGrestore,
418        }));
419        packets.push(Packet::nop());
420
421        packets.push(Packet::from(registers::CommandRegister{
422            command: registers::Command::LastFrame,
423        }));
424        packets.append(&mut vec![Packet::nop(); 100]);
425
426        packets.push(Packet::from(registers::CommandRegister{
427            command: registers::Command::Start,
428        }));
429        packets.push(Packet::nop());
430
431        packets.push(Packet::from(registers::FrameAddressRegister{
432            block_type: BlockType::Unknown,
433            device_half: DeviceHalf::Top,
434            row: 31.into(),
435            column: 0u16.into(),
436            minor: 0.into(),
437        }));
438        packets.push(Packet::from(registers::MaskRegister{
439            value: 0x501,
440        }));
441        packets.push(Packet::from(registers::ControlRegister0{
442            efuse_key: false,
443            icap_select:false,
444            over_temp_power_down: false,
445            config_fallback: true,
446            glutmask_b: true,
447            farsrc: false,
448            dec: false,
449            writes_disabled: false,
450            reads_disabled: false,
451            persist: false,
452            gts_usr_b: true,
453        }));
454        packets.push(Packet::nop());
455        packets.push(Packet::nop());
456
457        packets.push(Packet::from(registers::CommandRegister{
458            command: registers::Command::Desync,
459        }));
460        packets.append(&mut vec![Packet::nop(); 400]);
461
462        Bitstream{ packets }
463    }
464}