1use super::ranges::BitOffset;
2use super::SideMetadataSpec;
3use crate::util::constants::LOG_BYTES_IN_PAGE;
4use crate::util::constants::{BITS_IN_WORD, BYTES_IN_PAGE, LOG_BITS_IN_BYTE};
5use crate::util::conversions::rshift_align_up;
6use crate::util::heap::layout::vm_layout::VMLayout;
7#[cfg(target_pointer_width = "32")]
8use crate::util::metadata::side_metadata::address_to_chunked_meta_address;
9use crate::util::os::*;
10use crate::util::Address;
11use crate::MMAPPER;
12
13pub(super) fn address_to_contiguous_meta_address(
15 metadata_spec: &SideMetadataSpec,
16 data_addr: Address,
17) -> Address {
18 let log_bits_num = metadata_spec.log_num_of_bits as i32;
19 let log_bytes_in_region = metadata_spec.log_bytes_in_region;
20
21 let shift = (LOG_BITS_IN_BYTE as i32) - log_bits_num;
22
23 if shift >= 0 {
24 metadata_spec.get_starting_address() + ((data_addr >> log_bytes_in_region) >> shift)
25 } else {
26 metadata_spec.get_starting_address() + ((data_addr >> log_bytes_in_region) << (-shift))
27 }
28}
29
30pub(super) fn contiguous_meta_address_to_address(
38 metadata_spec: &SideMetadataSpec,
39 metadata_addr: Address,
40 bit: u8,
41) -> Address {
42 debug_assert_eq!(
43 align_metadata_address(metadata_spec, metadata_addr, bit),
44 (metadata_addr, bit)
45 );
46 let shift = (LOG_BITS_IN_BYTE as i32) - metadata_spec.log_num_of_bits as i32;
47 let relative_meta_addr = metadata_addr - metadata_spec.get_starting_address();
48
49 let data_addr_intermediate = if shift >= 0 {
50 relative_meta_addr << shift
51 } else {
52 relative_meta_addr >> (-shift)
53 };
54 let data_addr_bit_shift = if shift >= 0 {
55 metadata_spec.log_bytes_in_region - metadata_spec.log_num_of_bits
56 } else {
57 metadata_spec.log_bytes_in_region
58 };
59
60 let data_addr = (data_addr_intermediate << metadata_spec.log_bytes_in_region)
61 + ((bit as usize) << data_addr_bit_shift);
62
63 unsafe { Address::from_usize(data_addr) }
64}
65
66pub(super) fn align_metadata_address(
72 spec: &SideMetadataSpec,
73 metadata_addr: Address,
74 bit: u8,
75) -> (Address, u8) {
76 if spec.log_num_of_bits >= LOG_BITS_IN_BYTE as usize {
77 (
78 metadata_addr.align_down(1 << (spec.log_num_of_bits - LOG_BITS_IN_BYTE as usize)),
79 0,
80 )
81 } else {
82 (
83 metadata_addr,
84 crate::util::conversions::raw_align_down(
85 bit as usize,
86 (1 << spec.log_num_of_bits) as usize,
87 ) as u8,
88 )
89 }
90}
91
92#[cfg(test)]
94pub(crate) fn ensure_munmap_metadata(start: Address, size: usize) {
95 trace!("ensure_munmap_metadata({}, 0x{:x})", start, size);
96
97 assert!(OS::munmap(start, size).is_ok())
98}
99
100#[cfg(test)]
103pub(crate) fn ensure_munmap_contiguous_metadata_space(
104 start: Address,
105 size: usize,
106 spec: &SideMetadataSpec,
107) -> usize {
108 let metadata_start = address_to_meta_address(spec, start);
110 let mmap_start = metadata_start.align_down(BYTES_IN_PAGE);
111 let metadata_size = data_to_meta_size_round_up(spec, size);
113 let mmap_size = (metadata_start + metadata_size).align_up(BYTES_IN_PAGE) - mmap_start;
114 if mmap_size > 0 {
115 ensure_munmap_metadata(mmap_start, mmap_size);
116 }
117 mmap_size
118}
119
120pub(super) fn try_mmap_contiguous_metadata_space(
124 start: Address,
125 size: usize,
126 spec: &SideMetadataSpec,
127 no_reserve: bool,
128 anno: &MmapAnnotation,
129) -> MmapResult<usize> {
130 debug_assert!(start.is_aligned_to(BYTES_IN_PAGE));
131 debug_assert!(size % BYTES_IN_PAGE == 0);
132
133 let metadata_start = address_to_meta_address(spec, start);
135 let mmap_start = metadata_start.align_down(BYTES_IN_PAGE);
136 let metadata_size = data_to_meta_size_round_up(spec, size);
138 let mmap_size = (metadata_start + metadata_size).align_up(BYTES_IN_PAGE) - mmap_start;
139 if mmap_size > 0 {
140 if !no_reserve {
141 MMAPPER.ensure_mapped(
142 mmap_start,
143 mmap_size >> LOG_BYTES_IN_PAGE,
144 HugePageSupport::No,
145 MmapProtection::ReadWrite,
146 anno,
147 )
148 } else {
149 MMAPPER.quarantine_address_range(
150 mmap_start,
151 mmap_size >> LOG_BYTES_IN_PAGE,
152 HugePageSupport::No,
153 anno,
154 )
155 }
156 .map(|_| mmap_size)
157 } else {
158 Ok(0)
159 }
160}
161
162pub(crate) fn address_to_meta_address(
164 metadata_spec: &SideMetadataSpec,
165 data_addr: Address,
166) -> Address {
167 #[cfg(target_pointer_width = "32")]
168 let res = {
169 if metadata_spec.is_global {
170 address_to_contiguous_meta_address(metadata_spec, data_addr)
171 } else {
172 address_to_chunked_meta_address(metadata_spec, data_addr)
173 }
174 };
175 #[cfg(target_pointer_width = "64")]
176 let res = { address_to_contiguous_meta_address(metadata_spec, data_addr) };
177
178 trace!(
179 "address_to_meta_address({:?}, addr: {}) -> 0x{:x}",
180 metadata_spec,
181 data_addr,
182 res
183 );
184
185 res
186}
187
188pub(super) const fn log_data_meta_ratio(metadata_spec: &SideMetadataSpec) -> usize {
196 let log_data_bits_in_region = (LOG_BITS_IN_BYTE as usize) + metadata_spec.log_bytes_in_region;
197 let log_meta_bits_in_region = metadata_spec.log_num_of_bits;
198
199 log_data_bits_in_region - log_meta_bits_in_region
203}
204
205pub(super) const fn data_to_meta_size_round_up(
209 metadata_spec: &SideMetadataSpec,
210 data_size: usize,
211) -> usize {
212 rshift_align_up(data_size, log_data_meta_ratio(metadata_spec))
213}
214
215pub(super) const fn meta_to_data_size(metadata_spec: &SideMetadataSpec, meta_size: usize) -> usize {
218 meta_size << log_data_meta_ratio(metadata_spec)
219}
220
221#[allow(dead_code)]
222pub(super) const fn metadata_address_range_size(metadata_spec: &SideMetadataSpec) -> usize {
223 1usize << (VMLayout::LOG_ARCH_ADDRESS_SPACE - log_data_meta_ratio(metadata_spec))
224}
225
226pub(super) fn meta_byte_lshift(metadata_spec: &SideMetadataSpec, data_addr: Address) -> u8 {
227 let bits_num_log = metadata_spec.log_num_of_bits as i32;
228 if bits_num_log >= 3 {
229 return 0;
230 }
231 let rem_shift = BITS_IN_WORD as i32 - ((LOG_BITS_IN_BYTE as i32) - bits_num_log);
232 ((((data_addr >> metadata_spec.log_bytes_in_region) << rem_shift) >> rem_shift) << bits_num_log)
233 as u8
234}
235
236pub(super) fn meta_byte_mask(metadata_spec: &SideMetadataSpec) -> u8 {
237 let bits_num_log = metadata_spec.log_num_of_bits;
238 ((1usize << (1usize << bits_num_log)) - 1) as u8
239}
240
241pub enum FindMetaBitResult {
243 Found { addr: Address, bit: u8 },
244 NotFound,
245 UnmappedMetadata,
246}
247
248pub fn find_last_non_zero_bit_in_metadata_bytes(
250 meta_start: Address,
251 meta_end: Address,
252) -> FindMetaBitResult {
253 use crate::util::constants::BYTES_IN_ADDRESS;
254
255 let mmap_granularity = MMAPPER.granularity();
256
257 let mut cur = meta_end;
258 let mut mapped_grain = Address::MAX;
262 while cur > meta_start {
263 let step = if cur.is_aligned_to(BYTES_IN_ADDRESS) && cur - BYTES_IN_ADDRESS >= meta_start {
265 BYTES_IN_ADDRESS
266 } else {
267 1
268 };
269 cur -= step;
271 debug_assert!(
273 cur >= meta_start && cur < meta_end,
274 "Check metadata value at meta address {}, which is not in the range of [{}, {})",
275 cur,
276 meta_start,
277 meta_end
278 );
279
280 if cur < mapped_grain {
282 if cur.is_mapped() {
283 mapped_grain = cur.align_down(mmap_granularity);
285 } else {
286 return FindMetaBitResult::UnmappedMetadata;
287 }
288 }
289
290 if step == BYTES_IN_ADDRESS {
291 let value = unsafe { cur.load::<usize>() };
293 if value != 0 {
294 let bit = find_last_non_zero_bit::<usize>(value, 0, usize::BITS as u8).unwrap();
295 let byte_offset = bit >> LOG_BITS_IN_BYTE;
296 let bit_offset = bit - ((byte_offset) << LOG_BITS_IN_BYTE);
297 return FindMetaBitResult::Found {
298 addr: cur + byte_offset as usize,
299 bit: bit_offset,
300 };
301 }
302 } else {
303 let value = unsafe { cur.load::<u8>() };
305 if let Some(bit) = find_last_non_zero_bit::<u8>(value, 0, 8) {
306 return FindMetaBitResult::Found { addr: cur, bit };
307 }
308 }
309 }
310 FindMetaBitResult::NotFound
311}
312
313pub fn find_last_non_zero_bit_in_metadata_bits(
315 addr: Address,
316 start_bit: u8,
317 end_bit: u8,
318) -> FindMetaBitResult {
319 if !addr.is_mapped() {
320 return FindMetaBitResult::UnmappedMetadata;
321 }
322 let byte = unsafe { addr.load::<u8>() };
323 if let Some(bit) = find_last_non_zero_bit::<u8>(byte, start_bit, end_bit) {
324 return FindMetaBitResult::Found { addr, bit };
325 }
326 FindMetaBitResult::NotFound
327}
328
329use num_traits::{CheckedShl, PrimInt};
330fn find_last_non_zero_bit<T>(value: T, start: u8, end: u8) -> Option<u8>
331where
332 T: PrimInt + CheckedShl,
333{
334 let mask = match T::one().checked_shl((end - start) as u32) {
335 Some(shl) => (shl - T::one()) << (start as u32),
336 None => T::max_value() << (start as u32),
337 };
338 let masked = value & mask;
339 if masked.is_zero() {
340 None
341 } else {
342 let leading_zeroes = masked.leading_zeros();
343 let total_bits = std::mem::size_of::<T>() * u8::BITS as usize;
344 Some(total_bits as u8 - leading_zeroes as u8 - 1)
345 }
346}
347
348pub fn find_first_non_zero_bit_in_metadata_bytes(
349 meta_start: Address,
350 meta_end: Address,
351) -> FindMetaBitResult {
352 use crate::util::constants::BYTES_IN_ADDRESS;
353
354 let mmap_granularity = MMAPPER.granularity();
355
356 let mut cursor = meta_start;
357 let mut mapped_grain = Address::ZERO;
361 while cursor < meta_end {
362 let step =
364 if cursor.is_aligned_to(BYTES_IN_ADDRESS) && cursor + BYTES_IN_ADDRESS <= meta_end {
365 BYTES_IN_ADDRESS
366 } else {
367 1
368 };
369 debug_assert!(
371 cursor >= meta_start && cursor < meta_end,
372 "Check metadata value at meta address {}, which is not in the range of [{}, {})",
373 cursor,
374 meta_start,
375 meta_end
376 );
377
378 if cursor > mapped_grain {
380 if cursor.is_mapped() {
381 mapped_grain = cursor.align_up(mmap_granularity) - 0x1;
383 } else {
384 return FindMetaBitResult::UnmappedMetadata;
385 }
386 }
387
388 if step == BYTES_IN_ADDRESS {
389 let value = unsafe { cursor.load::<usize>() };
391 if value != 0 {
392 let bit = find_first_non_zero_bit::<usize>(value, 0, usize::BITS as u8).unwrap();
393 let byte_offset = bit >> LOG_BITS_IN_BYTE;
394 let bit_offset = bit - ((byte_offset) << LOG_BITS_IN_BYTE);
395 return FindMetaBitResult::Found {
396 addr: cursor + byte_offset as usize,
397 bit: bit_offset,
398 };
399 }
400 } else {
401 let value = unsafe { cursor.load::<u8>() };
403 if let Some(bit) = find_first_non_zero_bit::<u8>(value, 0, 8) {
404 return FindMetaBitResult::Found { addr: cursor, bit };
405 }
406 }
407 cursor += step;
409 }
410 FindMetaBitResult::NotFound
411}
412
413pub fn find_first_non_zero_bit_in_metadata_bits(
414 addr: Address,
415 start_bit: u8,
416 end_bit: u8,
417) -> FindMetaBitResult {
418 if !addr.is_mapped() {
419 return FindMetaBitResult::UnmappedMetadata;
420 }
421 let byte = unsafe { addr.load::<u8>() };
422 if let Some(bit) = find_first_non_zero_bit::<u8>(byte, start_bit, end_bit) {
423 return FindMetaBitResult::Found { addr, bit };
424 }
425 FindMetaBitResult::NotFound
426}
427
428fn find_first_non_zero_bit<T>(value: T, start: u8, end: u8) -> Option<u8>
429where
430 T: PrimInt + CheckedShl,
431{
432 let mask = match T::one().checked_shl((end - start) as u32) {
433 Some(shl) => (shl - T::one()) << (start as u32),
434 None => T::max_value() << (start as u32),
435 };
436 let masked = value & mask;
437 if masked.is_zero() {
438 None
439 } else {
440 let trailing_zeroes = masked.trailing_zeros();
441 Some(trailing_zeroes as u8)
442 }
443}
444
445pub fn scan_non_zero_bits_in_metadata_bytes(
446 meta_start: Address,
447 meta_end: Address,
448 visit_bit: &mut impl FnMut(Address, BitOffset),
449) {
450 use crate::util::constants::BYTES_IN_ADDRESS;
451
452 let mut cursor = meta_start;
453 while cursor < meta_end && !cursor.is_aligned_to(BYTES_IN_ADDRESS) {
454 let byte = unsafe { cursor.load::<u8>() };
455 scan_non_zero_bits_in_metadata_word(cursor, byte as usize, visit_bit);
456 cursor += 1usize;
457 }
458
459 while cursor + BYTES_IN_ADDRESS < meta_end {
460 let word = unsafe { cursor.load::<usize>() };
461 scan_non_zero_bits_in_metadata_word(cursor, word, visit_bit);
462 cursor += BYTES_IN_ADDRESS;
463 }
464
465 while cursor < meta_end {
466 let byte = unsafe { cursor.load::<u8>() };
467 scan_non_zero_bits_in_metadata_word(cursor, byte as usize, visit_bit);
468 cursor += 1usize;
469 }
470}
471
472fn scan_non_zero_bits_in_metadata_word(
473 meta_addr: Address,
474 mut word: usize,
475 visit_bit: &mut impl FnMut(Address, BitOffset),
476) {
477 while word != 0 {
478 let bit = word.trailing_zeros();
479 visit_bit(meta_addr, bit as u8);
480 word = word & (word - 1);
481 }
482}
483
484pub fn scan_non_zero_bits_in_metadata_bits(
485 meta_addr: Address,
486 bit_start: BitOffset,
487 bit_end: BitOffset,
488 visit_bit: &mut impl FnMut(Address, BitOffset),
489) {
490 let byte = unsafe { meta_addr.load::<u8>() };
491 for bit in bit_start..bit_end {
492 if byte & (1 << bit) != 0 {
493 visit_bit(meta_addr, bit);
494 }
495 }
496}
497
498#[cfg(test)]
499mod tests {
500 use super::*;
501 use crate::util::metadata::side_metadata::*;
502
503 fn should_skip_spec_on_this_target(spec: &SideMetadataSpec) -> bool {
504 use layout::LOG_GLOBAL_SIDE_METADATA_WORST_CASE_RATIO;
505 log_data_meta_ratio(spec) < LOG_GLOBAL_SIDE_METADATA_WORST_CASE_RATIO
506 }
507
508 fn test_round_trip_conversion(spec: &SideMetadataSpec, test_data: &[Address]) {
509 if should_skip_spec_on_this_target(spec) {
510 eprintln!(
511 "Skipping {} on this target: spec ratio is outside global side metadata worst-case bound",
512 spec.name
513 );
514 return;
515 }
516
517 core_test_initialize_side_metadata();
518
519 for ref_addr in test_data {
520 let addr = *ref_addr;
521
522 {
524 assert!(addr.is_aligned_to(1 << spec.log_bytes_in_region));
525 let meta_addr = address_to_contiguous_meta_address(spec, addr);
526 let shift = meta_byte_lshift(spec, addr);
527 assert_eq!(
528 contiguous_meta_address_to_address(spec, meta_addr, shift),
529 addr
530 );
531 }
532
533 {
535 let next_addr = addr + 1usize;
536 let meta_addr = address_to_contiguous_meta_address(spec, next_addr);
537 let shift = meta_byte_lshift(spec, next_addr);
538 assert_eq!(
539 contiguous_meta_address_to_address(spec, meta_addr, shift),
540 addr
541 ); }
543 }
544 }
545
546 const TEST_ADDRESS_8B_REGION: [Address; 8] = [
547 unsafe { Address::from_usize(0x8000_0000) },
548 unsafe { Address::from_usize(0x8000_0008) },
549 unsafe { Address::from_usize(0x8000_0010) },
550 unsafe { Address::from_usize(0x8000_0018) },
551 unsafe { Address::from_usize(0x8000_0020) },
552 unsafe { Address::from_usize(0x8001_0000) },
553 unsafe { Address::from_usize(0x8001_0008) },
554 unsafe { Address::from_usize(0xd000_0000) },
555 ];
556
557 #[test]
558 fn test_contiguous_metadata_conversion_0_3() {
559 let spec = SideMetadataSpec {
560 name: "ContiguousMetadataTestSpec",
561 is_global: true,
562 offset: 0,
563 log_num_of_bits: 0,
564 log_bytes_in_region: 3,
565 };
566
567 test_round_trip_conversion(&spec, &TEST_ADDRESS_8B_REGION);
568 }
569
570 #[test]
571 fn test_contiguous_metadata_conversion_1_3() {
572 let spec = SideMetadataSpec {
573 name: "ContiguousMetadataTestSpec",
574 is_global: true,
575 offset: 0,
576 log_num_of_bits: 1,
577 log_bytes_in_region: 3,
578 };
579
580 test_round_trip_conversion(&spec, &TEST_ADDRESS_8B_REGION);
581 }
582
583 #[test]
584 fn test_contiguous_metadata_conversion_4_3() {
585 let spec = SideMetadataSpec {
586 name: "ContiguousMetadataTestSpec",
587 is_global: true,
588 offset: 0,
589 log_num_of_bits: 4,
590 log_bytes_in_region: 3,
591 };
592
593 test_round_trip_conversion(&spec, &TEST_ADDRESS_8B_REGION);
594 }
595
596 #[test]
597 fn test_contiguous_metadata_conversion_5_3() {
598 let spec = SideMetadataSpec {
599 name: "ContiguousMetadataTestSpec",
600 is_global: true,
601 offset: 0,
602 log_num_of_bits: 5,
603 log_bytes_in_region: 3,
604 };
605
606 test_round_trip_conversion(&spec, &TEST_ADDRESS_8B_REGION);
607 }
608
609 const TEST_ADDRESS_4KB_REGION: [Address; 8] = [
610 unsafe { Address::from_usize(0x8000_0000) },
611 unsafe { Address::from_usize(0x8000_1000) },
612 unsafe { Address::from_usize(0x8000_2000) },
613 unsafe { Address::from_usize(0x8000_3000) },
614 unsafe { Address::from_usize(0x8000_4000) },
615 unsafe { Address::from_usize(0x8001_0000) },
616 unsafe { Address::from_usize(0x8001_1000) },
617 unsafe { Address::from_usize(0xd000_0000) },
618 ];
619
620 #[test]
621 fn test_contiguous_metadata_conversion_0_12() {
622 let spec = SideMetadataSpec {
623 name: "ContiguousMetadataTestSpec",
624 is_global: true,
625 offset: 0,
626 log_num_of_bits: 0,
627 log_bytes_in_region: 12, };
629
630 test_round_trip_conversion(&spec, &TEST_ADDRESS_4KB_REGION);
631 }
632
633 #[test]
634 fn test_find_last_non_zero_bit_in_u8() {
635 use super::find_last_non_zero_bit;
636 let bit = find_last_non_zero_bit::<u8>(0b100101, 0, 1);
637 assert_eq!(bit, Some(0));
638
639 let bit = find_last_non_zero_bit::<u8>(0b100101, 0, 3);
640 assert_eq!(bit, Some(2));
641
642 let bit = find_last_non_zero_bit::<u8>(0b100101, 0, 8);
643 assert_eq!(bit, Some(5));
644
645 let bit = find_last_non_zero_bit::<u8>(0b0, 0, 1);
646 assert_eq!(bit, None);
647 }
648
649 #[test]
650 fn test_align_metadata_address() {
651 let create_spec = |log_num_of_bits: usize| SideMetadataSpec {
652 name: "AlignMetadataBitTestSpec",
653 is_global: true,
654 offset: 0,
655 log_num_of_bits,
656 log_bytes_in_region: 3,
657 };
658
659 const ADDR_1000: Address = unsafe { Address::from_usize(0x1000) };
660 const ADDR_1001: Address = unsafe { Address::from_usize(0x1001) };
661 const ADDR_1002: Address = unsafe { Address::from_usize(0x1002) };
662 const ADDR_1003: Address = unsafe { Address::from_usize(0x1003) };
663 const ADDR_1004: Address = unsafe { Address::from_usize(0x1004) };
664 const ADDR_1005: Address = unsafe { Address::from_usize(0x1005) };
665 const ADDR_1006: Address = unsafe { Address::from_usize(0x1006) };
666 const ADDR_1007: Address = unsafe { Address::from_usize(0x1007) };
667 const ADDR_1008: Address = unsafe { Address::from_usize(0x1008) };
668 const ADDR_1009: Address = unsafe { Address::from_usize(0x1009) };
669
670 let metadata_2bits = create_spec(1);
671 assert_eq!(
672 align_metadata_address(&metadata_2bits, ADDR_1000, 0),
673 (ADDR_1000, 0)
674 );
675 assert_eq!(
676 align_metadata_address(&metadata_2bits, ADDR_1000, 1),
677 (ADDR_1000, 0)
678 );
679 assert_eq!(
680 align_metadata_address(&metadata_2bits, ADDR_1000, 2),
681 (ADDR_1000, 2)
682 );
683 assert_eq!(
684 align_metadata_address(&metadata_2bits, ADDR_1000, 3),
685 (ADDR_1000, 2)
686 );
687 assert_eq!(
688 align_metadata_address(&metadata_2bits, ADDR_1000, 4),
689 (ADDR_1000, 4)
690 );
691 assert_eq!(
692 align_metadata_address(&metadata_2bits, ADDR_1000, 5),
693 (ADDR_1000, 4)
694 );
695 assert_eq!(
696 align_metadata_address(&metadata_2bits, ADDR_1000, 6),
697 (ADDR_1000, 6)
698 );
699 assert_eq!(
700 align_metadata_address(&metadata_2bits, ADDR_1000, 7),
701 (ADDR_1000, 6)
702 );
703
704 let metadata_4bits = create_spec(2);
705 assert_eq!(
706 align_metadata_address(&metadata_4bits, ADDR_1000, 0),
707 (ADDR_1000, 0)
708 );
709 assert_eq!(
710 align_metadata_address(&metadata_4bits, ADDR_1000, 1),
711 (ADDR_1000, 0)
712 );
713 assert_eq!(
714 align_metadata_address(&metadata_4bits, ADDR_1000, 2),
715 (ADDR_1000, 0)
716 );
717 assert_eq!(
718 align_metadata_address(&metadata_4bits, ADDR_1000, 3),
719 (ADDR_1000, 0)
720 );
721 assert_eq!(
722 align_metadata_address(&metadata_4bits, ADDR_1000, 4),
723 (ADDR_1000, 4)
724 );
725 assert_eq!(
726 align_metadata_address(&metadata_4bits, ADDR_1000, 5),
727 (ADDR_1000, 4)
728 );
729 assert_eq!(
730 align_metadata_address(&metadata_4bits, ADDR_1000, 6),
731 (ADDR_1000, 4)
732 );
733 assert_eq!(
734 align_metadata_address(&metadata_4bits, ADDR_1000, 7),
735 (ADDR_1000, 4)
736 );
737
738 let metadata_8bits = create_spec(3);
739 assert_eq!(
740 align_metadata_address(&metadata_8bits, ADDR_1000, 0),
741 (ADDR_1000, 0)
742 );
743 assert_eq!(
744 align_metadata_address(&metadata_8bits, ADDR_1000, 1),
745 (ADDR_1000, 0)
746 );
747 assert_eq!(
748 align_metadata_address(&metadata_8bits, ADDR_1000, 2),
749 (ADDR_1000, 0)
750 );
751 assert_eq!(
752 align_metadata_address(&metadata_8bits, ADDR_1000, 3),
753 (ADDR_1000, 0)
754 );
755 assert_eq!(
756 align_metadata_address(&metadata_8bits, ADDR_1000, 4),
757 (ADDR_1000, 0)
758 );
759 assert_eq!(
760 align_metadata_address(&metadata_8bits, ADDR_1000, 5),
761 (ADDR_1000, 0)
762 );
763 assert_eq!(
764 align_metadata_address(&metadata_8bits, ADDR_1000, 6),
765 (ADDR_1000, 0)
766 );
767 assert_eq!(
768 align_metadata_address(&metadata_8bits, ADDR_1000, 7),
769 (ADDR_1000, 0)
770 );
771
772 let metadata_16bits = create_spec(4);
773 assert_eq!(
774 align_metadata_address(&metadata_16bits, ADDR_1000, 0),
775 (ADDR_1000, 0)
776 );
777 assert_eq!(
778 align_metadata_address(&metadata_16bits, ADDR_1000, 1),
779 (ADDR_1000, 0)
780 );
781 assert_eq!(
782 align_metadata_address(&metadata_16bits, ADDR_1000, 2),
783 (ADDR_1000, 0)
784 );
785 assert_eq!(
786 align_metadata_address(&metadata_16bits, ADDR_1000, 3),
787 (ADDR_1000, 0)
788 );
789 assert_eq!(
790 align_metadata_address(&metadata_16bits, ADDR_1000, 4),
791 (ADDR_1000, 0)
792 );
793 assert_eq!(
794 align_metadata_address(&metadata_16bits, ADDR_1000, 5),
795 (ADDR_1000, 0)
796 );
797 assert_eq!(
798 align_metadata_address(&metadata_16bits, ADDR_1000, 6),
799 (ADDR_1000, 0)
800 );
801 assert_eq!(
802 align_metadata_address(&metadata_16bits, ADDR_1000, 7),
803 (ADDR_1000, 0)
804 );
805 assert_eq!(
806 align_metadata_address(&metadata_16bits, ADDR_1001, 0),
807 (ADDR_1000, 0)
808 );
809 assert_eq!(
810 align_metadata_address(&metadata_16bits, ADDR_1001, 1),
811 (ADDR_1000, 0)
812 );
813 assert_eq!(
814 align_metadata_address(&metadata_16bits, ADDR_1001, 2),
815 (ADDR_1000, 0)
816 );
817 assert_eq!(
818 align_metadata_address(&metadata_16bits, ADDR_1001, 3),
819 (ADDR_1000, 0)
820 );
821 assert_eq!(
822 align_metadata_address(&metadata_16bits, ADDR_1001, 4),
823 (ADDR_1000, 0)
824 );
825 assert_eq!(
826 align_metadata_address(&metadata_16bits, ADDR_1001, 5),
827 (ADDR_1000, 0)
828 );
829 assert_eq!(
830 align_metadata_address(&metadata_16bits, ADDR_1001, 6),
831 (ADDR_1000, 0)
832 );
833 assert_eq!(
834 align_metadata_address(&metadata_16bits, ADDR_1001, 7),
835 (ADDR_1000, 0)
836 );
837 }
838}