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)]
164pub(super) struct FlashBuilder {
165 pub(super) data: BTreeMap<u64, Vec<u8>>,
166}
167
168impl FlashBuilder {
169 pub(super) fn new() -> Self {
171 Self {
172 data: BTreeMap::new(),
173 }
174 }
175
176 pub fn add_data(&mut self, address: u64, data: &[u8]) -> Result<(), FlashError> {
180 if data.is_empty() {
182 return Ok(());
183 }
184
185 if let Some((&next_addr, next_data)) = self.data.range(address..).next()
187 && address + (data.len() as u64) > next_addr
188 {
189 return Err(FlashError::DataOverlaps {
190 added_addresses: address..address + data.len() as u64,
191 existing_addresses: next_addr..next_addr + next_data.len() as u64,
192 });
193 }
194
195 if let Some((&prev_addr, prev_data)) = self.data.range_mut(..address).next_back() {
197 let prev_end = prev_addr + (prev_data.len() as u64);
198
199 if prev_end > address {
200 return Err(FlashError::DataOverlaps {
201 added_addresses: address..address + data.len() as u64,
202 existing_addresses: prev_addr..prev_addr + prev_data.len() as u64,
203 });
204 }
205
206 if prev_end == address {
208 prev_data.extend(data);
209 return Ok(());
210 }
211 }
212
213 self.data.insert(address, data.to_vec());
215
216 Ok(())
217 }
218
219 pub(crate) fn has_data_in_range(&self, range: &Range<u64>) -> bool {
221 self.data_in_range(range).next().is_some()
222 }
223
224 pub(crate) fn data_in_range<'s>(
231 &'s self,
232 range: &Range<u64>,
233 ) -> impl Iterator<Item = (u64, &'s [u8])> + use<'s> {
234 let range = range.clone();
235
236 let mut adjusted_start = range.start;
237
238 if let Some((&prev_addr, prev_data)) = self.data.range(..range.start).next_back()
241 && prev_addr + (prev_data.len() as u64) > range.start
242 {
243 adjusted_start = prev_addr;
244 }
245
246 self.data
247 .range(adjusted_start..range.end)
248 .map(move |(&addr, data)| {
249 let mut addr = addr;
250 let mut data = &data[..];
251
252 if addr < range.start {
254 data = &data[(range.start - addr) as usize..];
255 addr = range.start;
256 }
257
258 if addr + (data.len()) as u64 > range.end {
260 data = &data[..(range.end - addr) as usize];
261 }
262
263 (addr, data)
264 })
265 }
266
267 pub(super) fn build_sectors_and_pages(
269 &self,
270 region: &NvmRegion,
271 flash_algorithm: &FlashAlgorithm,
272 include_empty_pages: bool,
273 ) -> Result<FlashLayout, FlashError> {
274 let mut layout = FlashLayout::default();
275
276 for info in flash_algorithm.iter_sectors() {
277 let range = info.address_range();
278
279 if !region.range.contains_range(&range) {
281 continue;
282 }
283
284 let page = flash_algorithm.page_info(info.base_address).unwrap();
285 let page_range = page.address_range();
286 let sector_has_data = self.has_data_in_range(&range);
287 let page_has_data = self.has_data_in_range(&page_range);
288
289 if !sector_has_data && !page_has_data {
291 continue;
292 }
293
294 layout.sectors.push(FlashSector {
295 address: info.base_address,
296 size: info.size,
297 })
298 }
299
300 for info in flash_algorithm.iter_pages() {
301 let range = info.address_range();
302
303 if !region.range.contains_range(&range) {
305 continue;
306 }
307
308 let sector = flash_algorithm.sector_info(info.base_address).unwrap();
309 let sector_range = sector.address_range();
310 let sector_has_data = self.has_data_in_range(§or_range);
311 let page_has_data = self.has_data_in_range(&range);
312
313 if !page_has_data && (!include_empty_pages || !sector_has_data) {
315 continue;
316 }
317
318 let mut page =
319 FlashPage::new(&info, flash_algorithm.flash_properties.erased_byte_value);
320
321 let mut fill_start_addr = info.base_address;
322
323 for (address, data) in self.data_in_range(&range) {
325 let offset = (address - info.base_address) as usize;
327 page.data[offset..offset + data.len()].copy_from_slice(data);
328
329 if address > fill_start_addr {
331 layout.fills.push(FlashFill {
332 address: fill_start_addr,
333 size: address - fill_start_addr,
334 page_index: layout.pages.len(),
335 });
336 }
337 fill_start_addr = address + data.len() as u64;
338 }
339
340 if fill_start_addr < range.end {
342 layout.fills.push(FlashFill {
343 address: fill_start_addr,
344 size: range.end - fill_start_addr,
345 page_index: layout.pages.len(),
346 });
347 }
348
349 layout.pages.push(page);
350 }
351
352 for (address, data) in self.data_in_range(®ion.range) {
353 layout.data_blocks.push(FlashDataBlockSpan {
354 address,
355 size: data.len() as u64,
356 });
357 }
358
359 Ok(layout)
361 }
362}
363
364#[cfg(test)]
365mod tests {
366 use probe_rs_target::{FlashProperties, MemoryAccess, SectorDescription};
367
368 use super::*;
369
370 fn assemble_demo_flash1() -> (NvmRegion, FlashAlgorithm) {
371 let sd = SectorDescription {
372 size: 4096,
373 address: 0,
374 };
375
376 let flash_algorithm = FlashAlgorithm {
377 flash_properties: FlashProperties {
378 address_range: 0..1 << 16,
379 page_size: 1024,
380 erased_byte_value: 255,
381 program_page_timeout: 200,
382 erase_sector_timeout: 200,
383 sectors: vec![sd],
384 },
385 ..Default::default()
386 };
387
388 let region = NvmRegion {
389 name: Some("FLASH".into()),
390 access: Some(MemoryAccess {
391 boot: true,
392 ..Default::default()
393 }),
394 range: 0..1 << 16,
395 cores: vec!["main".into()],
396 is_alias: false,
397 };
398
399 (region, flash_algorithm)
400 }
401
402 fn assemble_demo_flash2() -> (NvmRegion, FlashAlgorithm) {
403 let sd = SectorDescription {
404 size: 128,
405 address: 0,
406 };
407
408 let flash_algorithm = FlashAlgorithm {
409 flash_properties: FlashProperties {
410 address_range: 0..1 << 16,
411 page_size: 1024,
412 erased_byte_value: 255,
413 program_page_timeout: 200,
414 erase_sector_timeout: 200,
415 sectors: vec![sd],
416 },
417 ..Default::default()
418 };
419
420 let region = NvmRegion {
421 name: Some("FLASH".into()),
422 access: Some(MemoryAccess {
423 boot: true,
424 ..Default::default()
425 }),
426 range: 0..1 << 16,
427 cores: vec!["main".into()],
428 is_alias: false,
429 };
430
431 (region, flash_algorithm)
432 }
433
434 #[test]
435 fn single_byte_in_single_page() {
436 let (region, flash_algorithm) = assemble_demo_flash1();
437 let mut flash_builder = FlashBuilder::new();
438 flash_builder.add_data(0, &[42]).unwrap();
439 let flash_layout = flash_builder
440 .build_sectors_and_pages(®ion, &flash_algorithm, true)
441 .unwrap();
442
443 let erased_byte_value = flash_algorithm.flash_properties.erased_byte_value;
444
445 assert_eq!(
446 flash_layout,
447 FlashLayout {
448 sectors: vec![FlashSector {
449 address: 0x0000,
450 size: 0x1000,
451 },],
452 pages: vec![
453 FlashPage {
454 address: 0x0000,
455 data: {
456 let mut data = vec![erased_byte_value; 1024];
457 data[0] = 42;
458 data
459 },
460 },
461 FlashPage {
462 address: 0x0400,
463 data: vec![erased_byte_value; 1024],
464 },
465 FlashPage {
466 address: 0x0800,
467 data: vec![erased_byte_value; 1024],
468 },
469 FlashPage {
470 address: 0x0C00,
471 data: vec![erased_byte_value; 1024],
472 },
473 ],
474 fills: vec![
475 FlashFill {
476 address: 0x0001,
477 size: 0x03FF,
478 page_index: 0,
479 },
480 FlashFill {
481 address: 0x0400,
482 size: 0x0400,
483 page_index: 1,
484 },
485 FlashFill {
486 address: 0x0800,
487 size: 0x0400,
488 page_index: 2,
489 },
490 FlashFill {
491 address: 0x0C00,
492 size: 0x0400,
493 page_index: 3,
494 }
495 ],
496 data_blocks: vec![FlashDataBlockSpan {
497 address: 0,
498 size: 1,
499 }],
500 }
501 )
502 }
503
504 #[test]
505 fn equal_bytes_full_single_page() {
506 let (region, flash_algorithm) = assemble_demo_flash1();
507 let mut flash_builder = FlashBuilder::new();
508 flash_builder.add_data(0, &[42; 1024]).unwrap();
509 let flash_layout = flash_builder
510 .build_sectors_and_pages(®ion, &flash_algorithm, true)
511 .unwrap();
512
513 let erased_byte_value = flash_algorithm.flash_properties.erased_byte_value;
514
515 assert_eq!(
516 flash_layout,
517 FlashLayout {
518 sectors: vec![FlashSector {
519 address: 0x0000,
520 size: 0x1000,
521 },],
522 pages: vec![
523 FlashPage {
524 address: 0x0000,
525 data: vec![42; 1024],
526 },
527 FlashPage {
528 address: 0x0400,
529 data: vec![erased_byte_value; 1024],
530 },
531 FlashPage {
532 address: 0x0800,
533 data: vec![erased_byte_value; 1024],
534 },
535 FlashPage {
536 address: 0x0C00,
537 data: vec![erased_byte_value; 1024],
538 },
539 ],
540 fills: vec![
541 FlashFill {
542 address: 0x0400,
543 size: 0x0400,
544 page_index: 1,
545 },
546 FlashFill {
547 address: 0x0800,
548 size: 0x0400,
549 page_index: 2,
550 },
551 FlashFill {
552 address: 0x0C00,
553 size: 0x0400,
554 page_index: 3,
555 }
556 ],
557 data_blocks: vec![FlashDataBlockSpan {
558 address: 0,
559 size: 1024,
560 }],
561 }
562 )
563 }
564
565 #[test]
566 fn equal_bytes_one_full_page_one_page_one_byte() {
567 let (region, flash_algorithm) = assemble_demo_flash1();
568 let mut flash_builder = FlashBuilder::new();
569 flash_builder.add_data(0, &[42; 1025]).unwrap();
570 let flash_layout = flash_builder
571 .build_sectors_and_pages(®ion, &flash_algorithm, true)
572 .unwrap();
573
574 let erased_byte_value = flash_algorithm.flash_properties.erased_byte_value;
575
576 assert_eq!(
577 flash_layout,
578 FlashLayout {
579 sectors: vec![FlashSector {
580 address: 0x0000,
581 size: 0x1000,
582 },],
583 pages: vec![
584 FlashPage {
585 address: 0x0000,
586 data: vec![42; 1024],
587 },
588 FlashPage {
589 address: 0x0400,
590 data: {
591 let mut data = vec![erased_byte_value; 1024];
592 data[0] = 42;
593 data
594 },
595 },
596 FlashPage {
597 address: 0x0800,
598 data: vec![erased_byte_value; 1024],
599 },
600 FlashPage {
601 address: 0x0C00,
602 data: vec![erased_byte_value; 1024],
603 },
604 ],
605 fills: vec![
606 FlashFill {
607 address: 0x0401,
608 size: 0x03FF,
609 page_index: 1,
610 },
611 FlashFill {
612 address: 0x0800,
613 size: 0x0400,
614 page_index: 2,
615 },
616 FlashFill {
617 address: 0x0C00,
618 size: 0x0400,
619 page_index: 3,
620 }
621 ],
622 data_blocks: vec![FlashDataBlockSpan {
623 address: 0,
624 size: 1025,
625 }],
626 }
627 )
628 }
629
630 #[test]
631 fn equal_bytes_one_full_page_one_page_one_byte_skip_fill() {
632 let (region, flash_algorithm) = assemble_demo_flash1();
633 let mut flash_builder = FlashBuilder::new();
634 flash_builder.add_data(0, &[42; 1025]).unwrap();
635 let flash_layout = flash_builder
636 .build_sectors_and_pages(®ion, &flash_algorithm, false)
637 .unwrap();
638
639 let erased_byte_value = flash_algorithm.flash_properties.erased_byte_value;
640
641 assert_eq!(
642 flash_layout,
643 FlashLayout {
644 sectors: vec![FlashSector {
645 address: 0x0000,
646 size: 0x1000,
647 },],
648 pages: vec![
649 FlashPage {
650 address: 0x0000,
651 data: vec![42; 1024],
652 },
653 FlashPage {
654 address: 0x0400,
655 data: {
656 let mut data = vec![erased_byte_value; 1024];
657 data[0] = 42;
658 data
659 },
660 },
661 ],
662 fills: vec![FlashFill {
663 address: 0x0401,
664 size: 0x03FF,
665 page_index: 1,
666 },],
667 data_blocks: vec![FlashDataBlockSpan {
668 address: 0,
669 size: 1025,
670 }],
671 }
672 )
673 }
674
675 #[test]
676 fn equal_bytes_one_page_from_offset_span_two_pages() {
677 let (region, flash_algorithm) = assemble_demo_flash1();
678 let mut flash_builder = FlashBuilder::new();
679 flash_builder.add_data(42, &[42; 1024]).unwrap();
680 let flash_layout = flash_builder
681 .build_sectors_and_pages(®ion, &flash_algorithm, true)
682 .unwrap();
683
684 let erased_byte_value = flash_algorithm.flash_properties.erased_byte_value;
685
686 assert_eq!(
687 flash_layout,
688 FlashLayout {
689 sectors: vec![FlashSector {
690 address: 0x000000,
691 size: 0x001000,
692 },],
693 pages: vec![
694 FlashPage {
695 address: 0x000000,
696 data: {
697 let mut data = vec![42; 1024];
698 for d in &mut data[..42] {
699 *d = erased_byte_value;
700 }
701 data
702 },
703 },
704 FlashPage {
705 address: 0x000400,
706 data: {
707 let mut data = vec![erased_byte_value; 1024];
708 for d in &mut data[..42] {
709 *d = 42;
710 }
711 data
712 },
713 },
714 FlashPage {
715 address: 0x000800,
716 data: vec![erased_byte_value; 1024],
717 },
718 FlashPage {
719 address: 0x000C00,
720 data: vec![erased_byte_value; 1024],
721 },
722 ],
723 fills: vec![
724 FlashFill {
725 address: 0x000000,
726 size: 0x00002A,
727 page_index: 0,
728 },
729 FlashFill {
730 address: 0x00042A,
731 size: 0x0003D6,
732 page_index: 1,
733 },
734 FlashFill {
735 address: 0x000800,
736 size: 0x000400,
737 page_index: 2,
738 },
739 FlashFill {
740 address: 0x000C00,
741 size: 0x000400,
742 page_index: 3,
743 },
744 ],
745 data_blocks: vec![FlashDataBlockSpan {
746 address: 42,
747 size: 1024,
748 },],
749 }
750 )
751 }
752
753 #[test]
754 fn equal_bytes_four_and_a_half_pages_two_sectors() {
755 let (region, flash_algorithm) = assemble_demo_flash1();
756 let mut flash_builder = FlashBuilder::new();
757 flash_builder.add_data(0, &[42; 5024]).unwrap();
758 let flash_layout = flash_builder
759 .build_sectors_and_pages(®ion, &flash_algorithm, true)
760 .unwrap();
761
762 let erased_byte_value = flash_algorithm.flash_properties.erased_byte_value;
763
764 assert_eq!(
765 flash_layout,
766 FlashLayout {
767 sectors: vec![
768 FlashSector {
769 address: 0x000000,
770 size: 0x001000,
771 },
772 FlashSector {
773 address: 0x001000,
774 size: 0x001000,
775 },
776 ],
777 pages: vec![
778 FlashPage {
779 address: 0x000000,
780 data: vec![42; 1024],
781 },
782 FlashPage {
783 address: 0x000400,
784 data: vec![42; 1024],
785 },
786 FlashPage {
787 address: 0x000800,
788 data: vec![42; 1024],
789 },
790 FlashPage {
791 address: 0x000C00,
792 data: vec![42; 1024],
793 },
794 FlashPage {
795 address: 0x001000,
796 data: {
797 let mut data = vec![erased_byte_value; 1024];
798 for d in &mut data[..928] {
799 *d = 42;
800 }
801 data
802 },
803 },
804 FlashPage {
805 address: 0x001400,
806 data: vec![erased_byte_value; 1024],
807 },
808 FlashPage {
809 address: 0x001800,
810 data: vec![erased_byte_value; 1024],
811 },
812 FlashPage {
813 address: 0x001C00,
814 data: vec![erased_byte_value; 1024],
815 },
816 ],
817 fills: vec![
818 FlashFill {
819 address: 0x0013A0,
820 size: 0x000060,
821 page_index: 4,
822 },
823 FlashFill {
824 address: 0x001400,
825 size: 0x000400,
826 page_index: 5,
827 },
828 FlashFill {
829 address: 0x001800,
830 size: 0x000400,
831 page_index: 6,
832 },
833 FlashFill {
834 address: 0x001C00,
835 size: 0x000400,
836 page_index: 7,
837 },
838 ],
839 data_blocks: vec![FlashDataBlockSpan {
840 address: 0,
841 size: 5024,
842 },],
843 }
844 )
845 }
846
847 #[test]
848 fn equal_bytes_in_two_data_chunks_multiple_sectors() {
849 let (region, flash_algorithm) = assemble_demo_flash1();
850 let mut flash_builder = FlashBuilder::new();
851 flash_builder.add_data(0, &[42; 5024]).unwrap();
852 flash_builder.add_data(7860, &[42; 5024]).unwrap();
853 let flash_layout = flash_builder
854 .build_sectors_and_pages(®ion, &flash_algorithm, true)
855 .unwrap();
856
857 let erased_byte_value = flash_algorithm.flash_properties.erased_byte_value;
858
859 assert_eq!(
860 flash_layout,
861 FlashLayout {
862 sectors: vec![
863 FlashSector {
864 address: 0x000000,
865 size: 0x001000,
866 },
867 FlashSector {
868 address: 0x001000,
869 size: 0x001000,
870 },
871 FlashSector {
872 address: 0x002000,
873 size: 0x001000,
874 },
875 FlashSector {
876 address: 0x003000,
877 size: 0x001000,
878 },
879 ],
880 pages: vec![
881 FlashPage {
882 address: 0x000000,
883 data: vec![42; 1024],
884 },
885 FlashPage {
886 address: 0x000400,
887 data: vec![42; 1024],
888 },
889 FlashPage {
890 address: 0x000800,
891 data: vec![42; 1024],
892 },
893 FlashPage {
894 address: 0x000C00,
895 data: vec![42; 1024],
896 },
897 FlashPage {
898 address: 0x001000,
899 data: {
900 let mut data = vec![42; 1024];
901 for d in &mut data[928..1024] {
902 *d = erased_byte_value;
903 }
904 data
905 },
906 },
907 FlashPage {
908 address: 0x001400,
909 data: vec![erased_byte_value; 1024],
910 },
911 FlashPage {
912 address: 0x001800,
913 data: vec![erased_byte_value; 1024],
914 },
915 FlashPage {
916 address: 0x001C00,
917 data: {
918 let mut data = vec![42; 1024];
919 for d in &mut data[..692] {
920 *d = erased_byte_value;
921 }
922 data
923 },
924 },
925 FlashPage {
926 address: 0x002000,
927 data: vec![42; 1024],
928 },
929 FlashPage {
930 address: 0x002400,
931 data: vec![42; 1024],
932 },
933 FlashPage {
934 address: 0x002800,
935 data: vec![42; 1024],
936 },
937 FlashPage {
938 address: 0x002C00,
939 data: vec![42; 1024],
940 },
941 FlashPage {
942 address: 0x003000,
943 data: {
944 let mut data = vec![42; 1024];
945 for d in &mut data[596..1024] {
946 *d = erased_byte_value;
947 }
948 data
949 },
950 },
951 FlashPage {
952 address: 0x003400,
953 data: vec![erased_byte_value; 1024],
954 },
955 FlashPage {
956 address: 0x003800,
957 data: vec![erased_byte_value; 1024],
958 },
959 FlashPage {
960 address: 0x003C00,
961 data: vec![erased_byte_value; 1024],
962 },
963 ],
964 fills: vec![
965 FlashFill {
966 address: 0x0013A0,
967 size: 0x000060,
968 page_index: 4,
969 },
970 FlashFill {
971 address: 0x001400,
972 size: 0x000400,
973 page_index: 5,
974 },
975 FlashFill {
976 address: 0x001800,
977 size: 0x000400,
978 page_index: 6,
979 },
980 FlashFill {
981 address: 0x001C00,
982 size: 0x0002B4,
983 page_index: 7,
984 },
985 FlashFill {
986 address: 0x003254,
987 size: 0x0001AC,
988 page_index: 12,
989 },
990 FlashFill {
991 address: 0x003400,
992 size: 0x000400,
993 page_index: 13,
994 },
995 FlashFill {
996 address: 0x003800,
997 size: 0x000400,
998 page_index: 14,
999 },
1000 FlashFill {
1001 address: 0x003C00,
1002 size: 0x000400,
1003 page_index: 15,
1004 },
1005 ],
1006 data_blocks: vec![
1007 FlashDataBlockSpan {
1008 address: 0,
1009 size: 5024,
1010 },
1011 FlashDataBlockSpan {
1012 address: 7860,
1013 size: 5024,
1014 },
1015 ],
1016 }
1017 )
1018 }
1019
1020 #[test]
1021 fn two_data_chunks_multiple_sectors_smaller_than_page() {
1022 let (region, flash_algorithm) = assemble_demo_flash2();
1023 let mut flash_builder = FlashBuilder::new();
1024 flash_builder.add_data(0, &[42; 5024]).unwrap();
1025 flash_builder.add_data(7860, &[42; 5024]).unwrap();
1026 let flash_layout = flash_builder
1027 .build_sectors_and_pages(®ion, &flash_algorithm, true)
1028 .unwrap();
1029
1030 let erased_byte_value = flash_algorithm.flash_properties.erased_byte_value;
1031
1032 assert_eq!(
1033 flash_layout,
1034 FlashLayout {
1035 sectors: {
1036 let mut sectors = Vec::with_capacity(88);
1037 for i in 0..40 {
1038 sectors.push(FlashSector {
1039 address: 128 * i as u64,
1040 size: 0x000080,
1041 });
1042 }
1043
1044 for i in 56..104 {
1045 sectors.push(FlashSector {
1046 address: 128 * i as u64,
1047 size: 0x000080,
1048 });
1049 }
1050
1051 sectors
1052 },
1053 pages: vec![
1054 FlashPage {
1055 address: 0x000000,
1056 data: vec![42; 1024],
1057 },
1058 FlashPage {
1059 address: 0x000400,
1060 data: vec![42; 1024],
1061 },
1062 FlashPage {
1063 address: 0x000800,
1064 data: vec![42; 1024],
1065 },
1066 FlashPage {
1067 address: 0x000C00,
1068 data: vec![42; 1024],
1069 },
1070 FlashPage {
1071 address: 0x001000,
1072 data: {
1073 let mut data = vec![42; 1024];
1074 for d in &mut data[928..1024] {
1075 *d = erased_byte_value;
1076 }
1077 data
1078 },
1079 },
1080 FlashPage {
1081 address: 0x001C00,
1082 data: {
1083 let mut data = vec![42; 1024];
1084 for d in &mut data[..692] {
1085 *d = erased_byte_value;
1086 }
1087 data
1088 },
1089 },
1090 FlashPage {
1091 address: 0x002000,
1092 data: vec![42; 1024],
1093 },
1094 FlashPage {
1095 address: 0x002400,
1096 data: vec![42; 1024],
1097 },
1098 FlashPage {
1099 address: 0x002800,
1100 data: vec![42; 1024],
1101 },
1102 FlashPage {
1103 address: 0x002C00,
1104 data: vec![42; 1024],
1105 },
1106 FlashPage {
1107 address: 0x003000,
1108 data: {
1109 let mut data = vec![42; 1024];
1110 for d in &mut data[596..1024] {
1111 *d = erased_byte_value;
1112 }
1113 data
1114 },
1115 },
1116 ],
1117 fills: vec![
1118 FlashFill {
1119 address: 0x0013A0,
1120 size: 0x000060,
1121 page_index: 4,
1122 },
1123 FlashFill {
1124 address: 0x001C00,
1125 size: 0x0002B4,
1126 page_index: 5,
1127 },
1128 FlashFill {
1129 address: 0x003254,
1130 size: 0x0001AC,
1131 page_index: 10,
1132 }
1133 ],
1134 data_blocks: vec![
1135 FlashDataBlockSpan {
1136 address: 0,
1137 size: 5024,
1138 },
1139 FlashDataBlockSpan {
1140 address: 7860,
1141 size: 5024,
1142 },
1143 ],
1144 }
1145 )
1146 }
1147}