Skip to main content

probe_rs/flashing/
builder.rs

1use std::collections::BTreeMap;
2use std::fmt::{Debug, Formatter};
3use std::ops::Range;
4
5use probe_rs_target::{MemoryRange, NvmRegion, PageInfo};
6
7use super::{FlashAlgorithm, FlashError};
8
9/// The description of a page in flash.
10#[derive(Clone, PartialEq, Eq)]
11pub struct FlashPage {
12    pub(super) address: u64,
13    pub(super) data: Vec<u8>,
14}
15
16impl Debug for FlashPage {
17    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
18        f.debug_struct("FlashPage")
19            .field("address", &self.address())
20            .field("size", &self.size())
21            .finish()
22    }
23}
24
25impl FlashPage {
26    /// Creates a new empty flash page from a `PageInfo`.
27    fn new(page_info: &PageInfo, default_value: u8) -> Self {
28        Self {
29            address: page_info.base_address,
30            data: vec![default_value; page_info.size as usize],
31        }
32    }
33
34    /// Returns the start address of the page.
35    pub fn address(&self) -> u64 {
36        self.address
37    }
38
39    /// Returns the size of the page in bytes.
40    pub fn size(&self) -> u32 {
41        self.data.len() as u32
42    }
43
44    /// Returns the data slice of the page.
45    pub fn data(&self) -> &[u8] {
46        &self.data
47    }
48
49    /// Returns the mut data slice of the page.
50    pub(super) fn data_mut(&mut self) -> &mut [u8] {
51        &mut self.data
52    }
53}
54
55/// The description of a sector in flash.
56#[derive(Clone, PartialEq, Eq, Debug)]
57pub struct FlashSector {
58    pub(crate) address: u64,
59    pub(crate) size: u64,
60}
61
62impl FlashSector {
63    /// Returns the start address of the sector.
64    pub fn address(&self) -> u64 {
65        self.address
66    }
67
68    /// Returns the size of the sector in bytes.
69    pub fn size(&self) -> u64 {
70        self.size
71    }
72}
73
74/// A struct to hold all the information about one region
75/// in the flash that is erased during flashing and has to be restored to its original value afterwards.
76#[derive(Clone, PartialEq, Eq, Debug)]
77pub struct FlashFill {
78    address: u64,
79    size: u64,
80    page_index: usize,
81}
82
83impl FlashFill {
84    /// Returns the start address of the fill.
85    pub fn address(&self) -> u64 {
86        self.address
87    }
88
89    /// Returns the size of the fill in bytes.
90    pub fn size(&self) -> u64 {
91        self.size
92    }
93
94    /// Returns the corresponding page index of the fill.
95    pub fn page_index(&self) -> usize {
96        self.page_index
97    }
98}
99
100/// The built layout of the data in flash.
101#[derive(Debug, Default, Clone, PartialEq, Eq)]
102pub struct FlashLayout {
103    pub(crate) sectors: Vec<FlashSector>,
104    pub(crate) pages: Vec<FlashPage>,
105    pub(crate) fills: Vec<FlashFill>,
106    data_blocks: Vec<FlashDataBlockSpan>,
107}
108
109impl FlashLayout {
110    /// Merge another flash layout into this one.
111    pub fn merge_from(&mut self, other: FlashLayout) {
112        self.sectors.extend(other.sectors);
113        self.pages.extend(other.pages);
114        self.fills.extend(other.fills);
115        self.data_blocks.extend(other.data_blocks);
116    }
117
118    /// List of sectors which are erased during flashing.
119    pub fn sectors(&self) -> &[FlashSector] {
120        &self.sectors
121    }
122
123    /// List of pages which are programmed during flashing.
124    pub fn pages(&self) -> &[FlashPage] {
125        &self.pages
126    }
127
128    /// Get the fills of the flash layout.
129    ///
130    /// This is data which is not written during flashing, but has to be restored to its original value afterwards.
131    pub fn fills(&self) -> &[FlashFill] {
132        &self.fills
133    }
134
135    /// Get the data blocks of the flash layout.
136    ///
137    /// This is the data which is written during flashing.
138    pub fn data_blocks(&self) -> &[FlashDataBlockSpan] {
139        &self.data_blocks
140    }
141}
142
143/// A block of data that is to be written to flash.
144#[derive(Clone, Copy, Debug, PartialEq, Eq)]
145pub struct FlashDataBlockSpan {
146    address: u64,
147    size: u64,
148}
149
150impl FlashDataBlockSpan {
151    /// Get the start address of the block.
152    pub fn address(&self) -> u64 {
153        self.address
154    }
155
156    /// Returns the size of the block in bytes.
157    pub fn size(&self) -> u64 {
158        self.size
159    }
160}
161
162/// A helper structure which caches all the raw data that needs to be flashed and allows building
163/// a flash layout from a set of data blocks.
164#[derive(Default)]
165pub struct FlashBuilder {
166    pub data: BTreeMap<u64, Vec<u8>>,
167}
168
169impl FlashBuilder {
170    /// Creates a new `FlashBuilder` with empty data.
171    pub fn new() -> Self {
172        Self {
173            data: BTreeMap::new(),
174        }
175    }
176
177    /// Stages a chunk of data to be programmed.
178    ///
179    /// The chunk can cross flash boundaries as long as one flash region connects to another flash region.
180    pub fn add_data(&mut self, address: u64, data: &[u8]) -> Result<(), FlashError> {
181        // Ignore zero-length stuff
182        if data.is_empty() {
183            return Ok(());
184        }
185
186        // Check the new data doesn't overlap to the right.
187        if let Some((&next_addr, next_data)) = self.data.range(address..).next()
188            && address + (data.len() as u64) > next_addr
189        {
190            return Err(FlashError::DataOverlaps {
191                added_addresses: address..address + data.len() as u64,
192                existing_addresses: next_addr..next_addr + next_data.len() as u64,
193            });
194        }
195
196        // Check the new data doesn't overlap to the left.
197        if let Some((&prev_addr, prev_data)) = self.data.range_mut(..address).next_back() {
198            let prev_end = prev_addr + (prev_data.len() as u64);
199
200            if prev_end > address {
201                return Err(FlashError::DataOverlaps {
202                    added_addresses: address..address + data.len() as u64,
203                    existing_addresses: prev_addr..prev_addr + prev_data.len() as u64,
204                });
205            }
206
207            // Optimization: If it exactly touches the left neighbor, extend it instead.
208            if prev_end == address {
209                prev_data.extend(data);
210                return Ok(());
211            }
212        }
213
214        // Add it
215        self.data.insert(address, data.to_vec());
216
217        Ok(())
218    }
219
220    /// Check whether there is staged data for a given address range.
221    pub(crate) fn has_data_in_range(&self, range: &Range<u64>) -> bool {
222        self.data_in_range(range).next().is_some()
223    }
224
225    /// Iterate staged data for a given address range.
226    ///
227    /// Data is returned in ascending address order, and is guaranteed not to overlap.
228    /// If a staged chunk is not fully contained in the range, only the contained part is
229    /// returned. ie for each returned item (addr, data), it's guaranteed that the condition
230    /// `start <= addr && addr + data.len() <= end` upholds.
231    pub(crate) fn data_in_range<'s>(
232        &'s self,
233        range: &Range<u64>,
234    ) -> impl Iterator<Item = (u64, &'s [u8])> + use<'s> {
235        let range = range.clone();
236
237        let mut adjusted_start = range.start;
238
239        // Check if the immediately preceding data overlaps with the wanted range.
240        // If so, adjust the iteration start so it is included.
241        if let Some((&prev_addr, prev_data)) = self.data.range(..range.start).next_back()
242            && prev_addr + (prev_data.len() as u64) > range.start
243        {
244            adjusted_start = prev_addr;
245        }
246
247        self.data
248            .range(adjusted_start..range.end)
249            .map(move |(&addr, data)| {
250                let mut addr = addr;
251                let mut data = &data[..];
252
253                // Cut chunk from the left if it starts before `start`.
254                if addr < range.start {
255                    data = &data[(range.start - addr) as usize..];
256                    addr = range.start;
257                }
258
259                // Cut chunk from the right if it ends before `end`.
260                if addr + (data.len()) as u64 > range.end {
261                    data = &data[..(range.end - addr) as usize];
262                }
263
264                (addr, data)
265            })
266    }
267
268    /// Layouts the contents of a flash memory according to the contents of the flash loader.
269    pub(super) fn build_sectors_and_pages(
270        &self,
271        region: &NvmRegion,
272        flash_algorithm: &FlashAlgorithm,
273        include_empty_pages: bool,
274    ) -> Result<FlashLayout, FlashError> {
275        let mut layout = FlashLayout::default();
276
277        for info in flash_algorithm.iter_sectors() {
278            let range = info.address_range();
279
280            // Ignore the sector if it's outside the NvmRegion.
281            if !region.range.contains_range(&range) {
282                continue;
283            }
284
285            let page = flash_algorithm.page_info(info.base_address).unwrap();
286            let page_range = page.address_range();
287            let sector_has_data = self.has_data_in_range(&range);
288            let page_has_data = self.has_data_in_range(&page_range);
289
290            // Ignore if neither the sector nor the page contain any data.
291            if !sector_has_data && !page_has_data {
292                continue;
293            }
294
295            layout.sectors.push(FlashSector {
296                address: info.base_address,
297                size: info.size,
298            })
299        }
300
301        for info in flash_algorithm.iter_pages() {
302            let range = info.address_range();
303
304            // Ignore the page if it's outside the NvmRegion.
305            if !region.range.contains_range(&range) {
306                continue;
307            }
308
309            let sector = flash_algorithm.sector_info(info.base_address).unwrap();
310            let sector_range = sector.address_range();
311            let sector_has_data = self.has_data_in_range(&sector_range);
312            let page_has_data = self.has_data_in_range(&range);
313
314            // If include_empty_pages, include the page if there's data in is sector, even if there's no data in the page.
315            if !page_has_data && (!include_empty_pages || !sector_has_data) {
316                continue;
317            }
318
319            let mut page =
320                FlashPage::new(&info, flash_algorithm.flash_properties.erased_byte_value);
321
322            let mut fill_start_addr = info.base_address;
323
324            // Loop over all datablocks in the page.
325            for (address, data) in self.data_in_range(&range) {
326                // Copy data into the page buffer
327                let offset = (address - info.base_address) as usize;
328                page.data[offset..offset + data.len()].copy_from_slice(data);
329
330                // Fill the hole between the previous data block (or page start if there are no blocks) and current block.
331                if address > fill_start_addr {
332                    layout.fills.push(FlashFill {
333                        address: fill_start_addr,
334                        size: address - fill_start_addr,
335                        page_index: layout.pages.len(),
336                    });
337                }
338                fill_start_addr = address + data.len() as u64;
339            }
340
341            // Fill the hole between the last data block (or page start if there are no blocks) and page end.
342            if fill_start_addr < range.end {
343                layout.fills.push(FlashFill {
344                    address: fill_start_addr,
345                    size: range.end - fill_start_addr,
346                    page_index: layout.pages.len(),
347                });
348            }
349
350            layout.pages.push(page);
351        }
352
353        for (address, data) in self.data_in_range(&region.range) {
354            layout.data_blocks.push(FlashDataBlockSpan {
355                address,
356                size: data.len() as u64,
357            });
358        }
359
360        // Return the finished flash layout.
361        Ok(layout)
362    }
363}
364
365#[cfg(test)]
366mod tests {
367    use probe_rs_target::{FlashProperties, MemoryAccess, SectorDescription};
368
369    use super::*;
370
371    fn assemble_demo_flash1() -> (NvmRegion, FlashAlgorithm) {
372        let sd = SectorDescription {
373            size: 4096,
374            address: 0,
375        };
376
377        let flash_algorithm = FlashAlgorithm {
378            flash_properties: FlashProperties {
379                address_range: 0..1 << 16,
380                page_size: 1024,
381                erased_byte_value: 255,
382                program_page_timeout: 200,
383                erase_sector_timeout: 200,
384                sectors: vec![sd],
385            },
386            ..Default::default()
387        };
388
389        let region = NvmRegion {
390            name: Some("FLASH".into()),
391            access: Some(MemoryAccess {
392                boot: true,
393                ..Default::default()
394            }),
395            range: 0..1 << 16,
396            cores: vec!["main".into()],
397            is_alias: false,
398        };
399
400        (region, flash_algorithm)
401    }
402
403    fn assemble_demo_flash2() -> (NvmRegion, FlashAlgorithm) {
404        let sd = SectorDescription {
405            size: 128,
406            address: 0,
407        };
408
409        let flash_algorithm = FlashAlgorithm {
410            flash_properties: FlashProperties {
411                address_range: 0..1 << 16,
412                page_size: 1024,
413                erased_byte_value: 255,
414                program_page_timeout: 200,
415                erase_sector_timeout: 200,
416                sectors: vec![sd],
417            },
418            ..Default::default()
419        };
420
421        let region = NvmRegion {
422            name: Some("FLASH".into()),
423            access: Some(MemoryAccess {
424                boot: true,
425                ..Default::default()
426            }),
427            range: 0..1 << 16,
428            cores: vec!["main".into()],
429            is_alias: false,
430        };
431
432        (region, flash_algorithm)
433    }
434
435    #[test]
436    fn single_byte_in_single_page() {
437        let (region, flash_algorithm) = assemble_demo_flash1();
438        let mut flash_builder = FlashBuilder::new();
439        flash_builder.add_data(0, &[42]).unwrap();
440        let flash_layout = flash_builder
441            .build_sectors_and_pages(&region, &flash_algorithm, true)
442            .unwrap();
443
444        let erased_byte_value = flash_algorithm.flash_properties.erased_byte_value;
445
446        assert_eq!(
447            flash_layout,
448            FlashLayout {
449                sectors: vec![FlashSector {
450                    address: 0x0000,
451                    size: 0x1000,
452                },],
453                pages: vec![
454                    FlashPage {
455                        address: 0x0000,
456                        data: {
457                            let mut data = vec![erased_byte_value; 1024];
458                            data[0] = 42;
459                            data
460                        },
461                    },
462                    FlashPage {
463                        address: 0x0400,
464                        data: vec![erased_byte_value; 1024],
465                    },
466                    FlashPage {
467                        address: 0x0800,
468                        data: vec![erased_byte_value; 1024],
469                    },
470                    FlashPage {
471                        address: 0x0C00,
472                        data: vec![erased_byte_value; 1024],
473                    },
474                ],
475                fills: vec![
476                    FlashFill {
477                        address: 0x0001,
478                        size: 0x03FF,
479                        page_index: 0,
480                    },
481                    FlashFill {
482                        address: 0x0400,
483                        size: 0x0400,
484                        page_index: 1,
485                    },
486                    FlashFill {
487                        address: 0x0800,
488                        size: 0x0400,
489                        page_index: 2,
490                    },
491                    FlashFill {
492                        address: 0x0C00,
493                        size: 0x0400,
494                        page_index: 3,
495                    }
496                ],
497                data_blocks: vec![FlashDataBlockSpan {
498                    address: 0,
499                    size: 1,
500                }],
501            }
502        )
503    }
504
505    #[test]
506    fn equal_bytes_full_single_page() {
507        let (region, flash_algorithm) = assemble_demo_flash1();
508        let mut flash_builder = FlashBuilder::new();
509        flash_builder.add_data(0, &[42; 1024]).unwrap();
510        let flash_layout = flash_builder
511            .build_sectors_and_pages(&region, &flash_algorithm, true)
512            .unwrap();
513
514        let erased_byte_value = flash_algorithm.flash_properties.erased_byte_value;
515
516        assert_eq!(
517            flash_layout,
518            FlashLayout {
519                sectors: vec![FlashSector {
520                    address: 0x0000,
521                    size: 0x1000,
522                },],
523                pages: vec![
524                    FlashPage {
525                        address: 0x0000,
526                        data: vec![42; 1024],
527                    },
528                    FlashPage {
529                        address: 0x0400,
530                        data: vec![erased_byte_value; 1024],
531                    },
532                    FlashPage {
533                        address: 0x0800,
534                        data: vec![erased_byte_value; 1024],
535                    },
536                    FlashPage {
537                        address: 0x0C00,
538                        data: vec![erased_byte_value; 1024],
539                    },
540                ],
541                fills: vec![
542                    FlashFill {
543                        address: 0x0400,
544                        size: 0x0400,
545                        page_index: 1,
546                    },
547                    FlashFill {
548                        address: 0x0800,
549                        size: 0x0400,
550                        page_index: 2,
551                    },
552                    FlashFill {
553                        address: 0x0C00,
554                        size: 0x0400,
555                        page_index: 3,
556                    }
557                ],
558                data_blocks: vec![FlashDataBlockSpan {
559                    address: 0,
560                    size: 1024,
561                }],
562            }
563        )
564    }
565
566    #[test]
567    fn equal_bytes_one_full_page_one_page_one_byte() {
568        let (region, flash_algorithm) = assemble_demo_flash1();
569        let mut flash_builder = FlashBuilder::new();
570        flash_builder.add_data(0, &[42; 1025]).unwrap();
571        let flash_layout = flash_builder
572            .build_sectors_and_pages(&region, &flash_algorithm, true)
573            .unwrap();
574
575        let erased_byte_value = flash_algorithm.flash_properties.erased_byte_value;
576
577        assert_eq!(
578            flash_layout,
579            FlashLayout {
580                sectors: vec![FlashSector {
581                    address: 0x0000,
582                    size: 0x1000,
583                },],
584                pages: vec![
585                    FlashPage {
586                        address: 0x0000,
587                        data: vec![42; 1024],
588                    },
589                    FlashPage {
590                        address: 0x0400,
591                        data: {
592                            let mut data = vec![erased_byte_value; 1024];
593                            data[0] = 42;
594                            data
595                        },
596                    },
597                    FlashPage {
598                        address: 0x0800,
599                        data: vec![erased_byte_value; 1024],
600                    },
601                    FlashPage {
602                        address: 0x0C00,
603                        data: vec![erased_byte_value; 1024],
604                    },
605                ],
606                fills: vec![
607                    FlashFill {
608                        address: 0x0401,
609                        size: 0x03FF,
610                        page_index: 1,
611                    },
612                    FlashFill {
613                        address: 0x0800,
614                        size: 0x0400,
615                        page_index: 2,
616                    },
617                    FlashFill {
618                        address: 0x0C00,
619                        size: 0x0400,
620                        page_index: 3,
621                    }
622                ],
623                data_blocks: vec![FlashDataBlockSpan {
624                    address: 0,
625                    size: 1025,
626                }],
627            }
628        )
629    }
630
631    #[test]
632    fn equal_bytes_one_full_page_one_page_one_byte_skip_fill() {
633        let (region, flash_algorithm) = assemble_demo_flash1();
634        let mut flash_builder = FlashBuilder::new();
635        flash_builder.add_data(0, &[42; 1025]).unwrap();
636        let flash_layout = flash_builder
637            .build_sectors_and_pages(&region, &flash_algorithm, false)
638            .unwrap();
639
640        let erased_byte_value = flash_algorithm.flash_properties.erased_byte_value;
641
642        assert_eq!(
643            flash_layout,
644            FlashLayout {
645                sectors: vec![FlashSector {
646                    address: 0x0000,
647                    size: 0x1000,
648                },],
649                pages: vec![
650                    FlashPage {
651                        address: 0x0000,
652                        data: vec![42; 1024],
653                    },
654                    FlashPage {
655                        address: 0x0400,
656                        data: {
657                            let mut data = vec![erased_byte_value; 1024];
658                            data[0] = 42;
659                            data
660                        },
661                    },
662                ],
663                fills: vec![FlashFill {
664                    address: 0x0401,
665                    size: 0x03FF,
666                    page_index: 1,
667                },],
668                data_blocks: vec![FlashDataBlockSpan {
669                    address: 0,
670                    size: 1025,
671                }],
672            }
673        )
674    }
675
676    #[test]
677    fn equal_bytes_one_page_from_offset_span_two_pages() {
678        let (region, flash_algorithm) = assemble_demo_flash1();
679        let mut flash_builder = FlashBuilder::new();
680        flash_builder.add_data(42, &[42; 1024]).unwrap();
681        let flash_layout = flash_builder
682            .build_sectors_and_pages(&region, &flash_algorithm, true)
683            .unwrap();
684
685        let erased_byte_value = flash_algorithm.flash_properties.erased_byte_value;
686
687        assert_eq!(
688            flash_layout,
689            FlashLayout {
690                sectors: vec![FlashSector {
691                    address: 0x000000,
692                    size: 0x001000,
693                },],
694                pages: vec![
695                    FlashPage {
696                        address: 0x000000,
697                        data: {
698                            let mut data = vec![42; 1024];
699                            for d in &mut data[..42] {
700                                *d = erased_byte_value;
701                            }
702                            data
703                        },
704                    },
705                    FlashPage {
706                        address: 0x000400,
707                        data: {
708                            let mut data = vec![erased_byte_value; 1024];
709                            for d in &mut data[..42] {
710                                *d = 42;
711                            }
712                            data
713                        },
714                    },
715                    FlashPage {
716                        address: 0x000800,
717                        data: vec![erased_byte_value; 1024],
718                    },
719                    FlashPage {
720                        address: 0x000C00,
721                        data: vec![erased_byte_value; 1024],
722                    },
723                ],
724                fills: vec![
725                    FlashFill {
726                        address: 0x000000,
727                        size: 0x00002A,
728                        page_index: 0,
729                    },
730                    FlashFill {
731                        address: 0x00042A,
732                        size: 0x0003D6,
733                        page_index: 1,
734                    },
735                    FlashFill {
736                        address: 0x000800,
737                        size: 0x000400,
738                        page_index: 2,
739                    },
740                    FlashFill {
741                        address: 0x000C00,
742                        size: 0x000400,
743                        page_index: 3,
744                    },
745                ],
746                data_blocks: vec![FlashDataBlockSpan {
747                    address: 42,
748                    size: 1024,
749                },],
750            }
751        )
752    }
753
754    #[test]
755    fn equal_bytes_four_and_a_half_pages_two_sectors() {
756        let (region, flash_algorithm) = assemble_demo_flash1();
757        let mut flash_builder = FlashBuilder::new();
758        flash_builder.add_data(0, &[42; 5024]).unwrap();
759        let flash_layout = flash_builder
760            .build_sectors_and_pages(&region, &flash_algorithm, true)
761            .unwrap();
762
763        let erased_byte_value = flash_algorithm.flash_properties.erased_byte_value;
764
765        assert_eq!(
766            flash_layout,
767            FlashLayout {
768                sectors: vec![
769                    FlashSector {
770                        address: 0x000000,
771                        size: 0x001000,
772                    },
773                    FlashSector {
774                        address: 0x001000,
775                        size: 0x001000,
776                    },
777                ],
778                pages: vec![
779                    FlashPage {
780                        address: 0x000000,
781                        data: vec![42; 1024],
782                    },
783                    FlashPage {
784                        address: 0x000400,
785                        data: vec![42; 1024],
786                    },
787                    FlashPage {
788                        address: 0x000800,
789                        data: vec![42; 1024],
790                    },
791                    FlashPage {
792                        address: 0x000C00,
793                        data: vec![42; 1024],
794                    },
795                    FlashPage {
796                        address: 0x001000,
797                        data: {
798                            let mut data = vec![erased_byte_value; 1024];
799                            for d in &mut data[..928] {
800                                *d = 42;
801                            }
802                            data
803                        },
804                    },
805                    FlashPage {
806                        address: 0x001400,
807                        data: vec![erased_byte_value; 1024],
808                    },
809                    FlashPage {
810                        address: 0x001800,
811                        data: vec![erased_byte_value; 1024],
812                    },
813                    FlashPage {
814                        address: 0x001C00,
815                        data: vec![erased_byte_value; 1024],
816                    },
817                ],
818                fills: vec![
819                    FlashFill {
820                        address: 0x0013A0,
821                        size: 0x000060,
822                        page_index: 4,
823                    },
824                    FlashFill {
825                        address: 0x001400,
826                        size: 0x000400,
827                        page_index: 5,
828                    },
829                    FlashFill {
830                        address: 0x001800,
831                        size: 0x000400,
832                        page_index: 6,
833                    },
834                    FlashFill {
835                        address: 0x001C00,
836                        size: 0x000400,
837                        page_index: 7,
838                    },
839                ],
840                data_blocks: vec![FlashDataBlockSpan {
841                    address: 0,
842                    size: 5024,
843                },],
844            }
845        )
846    }
847
848    #[test]
849    fn equal_bytes_in_two_data_chunks_multiple_sectors() {
850        let (region, flash_algorithm) = assemble_demo_flash1();
851        let mut flash_builder = FlashBuilder::new();
852        flash_builder.add_data(0, &[42; 5024]).unwrap();
853        flash_builder.add_data(7860, &[42; 5024]).unwrap();
854        let flash_layout = flash_builder
855            .build_sectors_and_pages(&region, &flash_algorithm, true)
856            .unwrap();
857
858        let erased_byte_value = flash_algorithm.flash_properties.erased_byte_value;
859
860        assert_eq!(
861            flash_layout,
862            FlashLayout {
863                sectors: vec![
864                    FlashSector {
865                        address: 0x000000,
866                        size: 0x001000,
867                    },
868                    FlashSector {
869                        address: 0x001000,
870                        size: 0x001000,
871                    },
872                    FlashSector {
873                        address: 0x002000,
874                        size: 0x001000,
875                    },
876                    FlashSector {
877                        address: 0x003000,
878                        size: 0x001000,
879                    },
880                ],
881                pages: vec![
882                    FlashPage {
883                        address: 0x000000,
884                        data: vec![42; 1024],
885                    },
886                    FlashPage {
887                        address: 0x000400,
888                        data: vec![42; 1024],
889                    },
890                    FlashPage {
891                        address: 0x000800,
892                        data: vec![42; 1024],
893                    },
894                    FlashPage {
895                        address: 0x000C00,
896                        data: vec![42; 1024],
897                    },
898                    FlashPage {
899                        address: 0x001000,
900                        data: {
901                            let mut data = vec![42; 1024];
902                            for d in &mut data[928..1024] {
903                                *d = erased_byte_value;
904                            }
905                            data
906                        },
907                    },
908                    FlashPage {
909                        address: 0x001400,
910                        data: vec![erased_byte_value; 1024],
911                    },
912                    FlashPage {
913                        address: 0x001800,
914                        data: vec![erased_byte_value; 1024],
915                    },
916                    FlashPage {
917                        address: 0x001C00,
918                        data: {
919                            let mut data = vec![42; 1024];
920                            for d in &mut data[..692] {
921                                *d = erased_byte_value;
922                            }
923                            data
924                        },
925                    },
926                    FlashPage {
927                        address: 0x002000,
928                        data: vec![42; 1024],
929                    },
930                    FlashPage {
931                        address: 0x002400,
932                        data: vec![42; 1024],
933                    },
934                    FlashPage {
935                        address: 0x002800,
936                        data: vec![42; 1024],
937                    },
938                    FlashPage {
939                        address: 0x002C00,
940                        data: vec![42; 1024],
941                    },
942                    FlashPage {
943                        address: 0x003000,
944                        data: {
945                            let mut data = vec![42; 1024];
946                            for d in &mut data[596..1024] {
947                                *d = erased_byte_value;
948                            }
949                            data
950                        },
951                    },
952                    FlashPage {
953                        address: 0x003400,
954                        data: vec![erased_byte_value; 1024],
955                    },
956                    FlashPage {
957                        address: 0x003800,
958                        data: vec![erased_byte_value; 1024],
959                    },
960                    FlashPage {
961                        address: 0x003C00,
962                        data: vec![erased_byte_value; 1024],
963                    },
964                ],
965                fills: vec![
966                    FlashFill {
967                        address: 0x0013A0,
968                        size: 0x000060,
969                        page_index: 4,
970                    },
971                    FlashFill {
972                        address: 0x001400,
973                        size: 0x000400,
974                        page_index: 5,
975                    },
976                    FlashFill {
977                        address: 0x001800,
978                        size: 0x000400,
979                        page_index: 6,
980                    },
981                    FlashFill {
982                        address: 0x001C00,
983                        size: 0x0002B4,
984                        page_index: 7,
985                    },
986                    FlashFill {
987                        address: 0x003254,
988                        size: 0x0001AC,
989                        page_index: 12,
990                    },
991                    FlashFill {
992                        address: 0x003400,
993                        size: 0x000400,
994                        page_index: 13,
995                    },
996                    FlashFill {
997                        address: 0x003800,
998                        size: 0x000400,
999                        page_index: 14,
1000                    },
1001                    FlashFill {
1002                        address: 0x003C00,
1003                        size: 0x000400,
1004                        page_index: 15,
1005                    },
1006                ],
1007                data_blocks: vec![
1008                    FlashDataBlockSpan {
1009                        address: 0,
1010                        size: 5024,
1011                    },
1012                    FlashDataBlockSpan {
1013                        address: 7860,
1014                        size: 5024,
1015                    },
1016                ],
1017            }
1018        )
1019    }
1020
1021    #[test]
1022    fn two_data_chunks_multiple_sectors_smaller_than_page() {
1023        let (region, flash_algorithm) = assemble_demo_flash2();
1024        let mut flash_builder = FlashBuilder::new();
1025        flash_builder.add_data(0, &[42; 5024]).unwrap();
1026        flash_builder.add_data(7860, &[42; 5024]).unwrap();
1027        let flash_layout = flash_builder
1028            .build_sectors_and_pages(&region, &flash_algorithm, true)
1029            .unwrap();
1030
1031        let erased_byte_value = flash_algorithm.flash_properties.erased_byte_value;
1032
1033        assert_eq!(
1034            flash_layout,
1035            FlashLayout {
1036                sectors: {
1037                    let mut sectors = Vec::with_capacity(88);
1038                    for i in 0..40 {
1039                        sectors.push(FlashSector {
1040                            address: 128 * i as u64,
1041                            size: 0x000080,
1042                        });
1043                    }
1044
1045                    for i in 56..104 {
1046                        sectors.push(FlashSector {
1047                            address: 128 * i as u64,
1048                            size: 0x000080,
1049                        });
1050                    }
1051
1052                    sectors
1053                },
1054                pages: vec![
1055                    FlashPage {
1056                        address: 0x000000,
1057                        data: vec![42; 1024],
1058                    },
1059                    FlashPage {
1060                        address: 0x000400,
1061                        data: vec![42; 1024],
1062                    },
1063                    FlashPage {
1064                        address: 0x000800,
1065                        data: vec![42; 1024],
1066                    },
1067                    FlashPage {
1068                        address: 0x000C00,
1069                        data: vec![42; 1024],
1070                    },
1071                    FlashPage {
1072                        address: 0x001000,
1073                        data: {
1074                            let mut data = vec![42; 1024];
1075                            for d in &mut data[928..1024] {
1076                                *d = erased_byte_value;
1077                            }
1078                            data
1079                        },
1080                    },
1081                    FlashPage {
1082                        address: 0x001C00,
1083                        data: {
1084                            let mut data = vec![42; 1024];
1085                            for d in &mut data[..692] {
1086                                *d = erased_byte_value;
1087                            }
1088                            data
1089                        },
1090                    },
1091                    FlashPage {
1092                        address: 0x002000,
1093                        data: vec![42; 1024],
1094                    },
1095                    FlashPage {
1096                        address: 0x002400,
1097                        data: vec![42; 1024],
1098                    },
1099                    FlashPage {
1100                        address: 0x002800,
1101                        data: vec![42; 1024],
1102                    },
1103                    FlashPage {
1104                        address: 0x002C00,
1105                        data: vec![42; 1024],
1106                    },
1107                    FlashPage {
1108                        address: 0x003000,
1109                        data: {
1110                            let mut data = vec![42; 1024];
1111                            for d in &mut data[596..1024] {
1112                                *d = erased_byte_value;
1113                            }
1114                            data
1115                        },
1116                    },
1117                ],
1118                fills: vec![
1119                    FlashFill {
1120                        address: 0x0013A0,
1121                        size: 0x000060,
1122                        page_index: 4,
1123                    },
1124                    FlashFill {
1125                        address: 0x001C00,
1126                        size: 0x0002B4,
1127                        page_index: 5,
1128                    },
1129                    FlashFill {
1130                        address: 0x003254,
1131                        size: 0x0001AC,
1132                        page_index: 10,
1133                    }
1134                ],
1135                data_blocks: vec![
1136                    FlashDataBlockSpan {
1137                        address: 0,
1138                        size: 5024,
1139                    },
1140                    FlashDataBlockSpan {
1141                        address: 7860,
1142                        size: 5024,
1143                    },
1144                ],
1145            }
1146        )
1147    }
1148}