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#[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 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 pub fn address(&self) -> u64 {
36 self.address
37 }
38
39 pub fn size(&self) -> u32 {
41 self.data.len() as u32
42 }
43
44 pub fn data(&self) -> &[u8] {
46 &self.data
47 }
48
49 pub(super) fn data_mut(&mut self) -> &mut [u8] {
51 &mut self.data
52 }
53}
54
55#[derive(Clone, PartialEq, Eq, Debug)]
57pub struct FlashSector {
58 pub(crate) address: u64,
59 pub(crate) size: u64,
60}
61
62impl FlashSector {
63 pub fn address(&self) -> u64 {
65 self.address
66 }
67
68 pub fn size(&self) -> u64 {
70 self.size
71 }
72}
73
74#[derive(Clone, PartialEq, Eq, Debug)]
77pub struct FlashFill {
78 address: u64,
79 size: u64,
80 page_index: usize,
81}
82
83impl FlashFill {
84 pub fn address(&self) -> u64 {
86 self.address
87 }
88
89 pub fn size(&self) -> u64 {
91 self.size
92 }
93
94 pub fn page_index(&self) -> usize {
96 self.page_index
97 }
98}
99
100#[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 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 pub fn sectors(&self) -> &[FlashSector] {
120 &self.sectors
121 }
122
123 pub fn pages(&self) -> &[FlashPage] {
125 &self.pages
126 }
127
128 pub fn fills(&self) -> &[FlashFill] {
132 &self.fills
133 }
134
135 pub fn data_blocks(&self) -> &[FlashDataBlockSpan] {
139 &self.data_blocks
140 }
141}
142
143#[derive(Clone, Copy, Debug, PartialEq, Eq)]
145pub struct FlashDataBlockSpan {
146 address: u64,
147 size: u64,
148}
149
150impl FlashDataBlockSpan {
151 pub fn address(&self) -> u64 {
153 self.address
154 }
155
156 pub fn size(&self) -> u64 {
158 self.size
159 }
160}
161
162#[derive(Default)]
165pub struct FlashBuilder {
166 pub data: BTreeMap<u64, Vec<u8>>,
167}
168
169impl FlashBuilder {
170 pub fn new() -> Self {
172 Self {
173 data: BTreeMap::new(),
174 }
175 }
176
177 pub fn add_data(&mut self, address: u64, data: &[u8]) -> Result<(), FlashError> {
181 if data.is_empty() {
183 return Ok(());
184 }
185
186 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 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 if prev_end == address {
209 prev_data.extend(data);
210 return Ok(());
211 }
212 }
213
214 self.data.insert(address, data.to_vec());
216
217 Ok(())
218 }
219
220 pub(crate) fn has_data_in_range(&self, range: &Range<u64>) -> bool {
222 self.data_in_range(range).next().is_some()
223 }
224
225 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 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 if addr < range.start {
255 data = &data[(range.start - addr) as usize..];
256 addr = range.start;
257 }
258
259 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 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 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 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 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(§or_range);
312 let page_has_data = self.has_data_in_range(&range);
313
314 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 for (address, data) in self.data_in_range(&range) {
326 let offset = (address - info.base_address) as usize;
328 page.data[offset..offset + data.len()].copy_from_slice(data);
329
330 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 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(®ion.range) {
354 layout.data_blocks.push(FlashDataBlockSpan {
355 address,
356 size: data.len() as u64,
357 });
358 }
359
360 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(®ion, &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(®ion, &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(®ion, &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(®ion, &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(®ion, &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(®ion, &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(®ion, &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(®ion, &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}