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 .inspect_err(|_| {
158 warn!(
159 "Failed to mmap metadata space: {} - {}",
160 mmap_start,
161 mmap_start + mmap_size
162 );
163 })
164 } else {
165 Ok(0)
166 }
167}
168
169pub(crate) fn address_to_meta_address(
171 metadata_spec: &SideMetadataSpec,
172 data_addr: Address,
173) -> Address {
174 #[cfg(target_pointer_width = "32")]
175 let res = {
176 if metadata_spec.is_global {
177 address_to_contiguous_meta_address(metadata_spec, data_addr)
178 } else {
179 address_to_chunked_meta_address(metadata_spec, data_addr)
180 }
181 };
182 #[cfg(target_pointer_width = "64")]
183 let res = { address_to_contiguous_meta_address(metadata_spec, data_addr) };
184
185 trace!(
186 "address_to_meta_address({:?}, addr: {}) -> 0x{:x}",
187 metadata_spec,
188 data_addr,
189 res
190 );
191
192 res
193}
194
195pub(super) const fn log_data_meta_ratio(metadata_spec: &SideMetadataSpec) -> usize {
203 let log_data_bits_in_region = (LOG_BITS_IN_BYTE as usize) + metadata_spec.log_bytes_in_region;
204 let log_meta_bits_in_region = metadata_spec.log_num_of_bits;
205
206 log_data_bits_in_region - log_meta_bits_in_region
210}
211
212pub(super) const fn data_to_meta_size_round_up(
216 metadata_spec: &SideMetadataSpec,
217 data_size: usize,
218) -> usize {
219 rshift_align_up(data_size, log_data_meta_ratio(metadata_spec))
220}
221
222pub(super) const fn meta_to_data_size(metadata_spec: &SideMetadataSpec, meta_size: usize) -> usize {
225 meta_size << log_data_meta_ratio(metadata_spec)
226}
227
228#[allow(dead_code)]
229pub(super) const fn metadata_address_range_size(metadata_spec: &SideMetadataSpec) -> usize {
230 1usize << (VMLayout::LOG_ARCH_ADDRESS_SPACE - log_data_meta_ratio(metadata_spec))
231}
232
233pub(super) fn meta_byte_lshift(metadata_spec: &SideMetadataSpec, data_addr: Address) -> u8 {
234 let bits_num_log = metadata_spec.log_num_of_bits as i32;
235 if bits_num_log >= 3 {
236 return 0;
237 }
238 let rem_shift = BITS_IN_WORD as i32 - ((LOG_BITS_IN_BYTE as i32) - bits_num_log);
239 ((((data_addr >> metadata_spec.log_bytes_in_region) << rem_shift) >> rem_shift) << bits_num_log)
240 as u8
241}
242
243pub(super) fn meta_byte_mask(metadata_spec: &SideMetadataSpec) -> u8 {
244 let bits_num_log = metadata_spec.log_num_of_bits;
245 ((1usize << (1usize << bits_num_log)) - 1) as u8
246}
247
248pub enum FindMetaBitResult {
250 Found { addr: Address, bit: u8 },
251 NotFound,
252 UnmappedMetadata,
253}
254
255pub fn find_last_non_zero_bit_in_metadata_bytes(
257 meta_start: Address,
258 meta_end: Address,
259) -> FindMetaBitResult {
260 use crate::util::constants::BYTES_IN_ADDRESS;
261
262 let mmap_granularity = MMAPPER.granularity();
263
264 let mut cur = meta_end;
265 let mut mapped_grain = Address::MAX;
269 while cur > meta_start {
270 let step = if cur.is_aligned_to(BYTES_IN_ADDRESS) && cur - BYTES_IN_ADDRESS >= meta_start {
272 BYTES_IN_ADDRESS
273 } else {
274 1
275 };
276 cur -= step;
278 debug_assert!(
280 cur >= meta_start && cur < meta_end,
281 "Check metadata value at meta address {}, which is not in the range of [{}, {})",
282 cur,
283 meta_start,
284 meta_end
285 );
286
287 if cur < mapped_grain {
289 if cur.is_mapped() {
290 mapped_grain = cur.align_down(mmap_granularity);
292 } else {
293 return FindMetaBitResult::UnmappedMetadata;
294 }
295 }
296
297 if step == BYTES_IN_ADDRESS {
298 let value = unsafe { cur.load::<usize>() };
300 if value != 0 {
301 let bit = find_last_non_zero_bit::<usize>(value, 0, usize::BITS as u8).unwrap();
302 let byte_offset = bit >> LOG_BITS_IN_BYTE;
303 let bit_offset = bit - ((byte_offset) << LOG_BITS_IN_BYTE);
304 return FindMetaBitResult::Found {
305 addr: cur + byte_offset as usize,
306 bit: bit_offset,
307 };
308 }
309 } else {
310 let value = unsafe { cur.load::<u8>() };
312 if let Some(bit) = find_last_non_zero_bit::<u8>(value, 0, 8) {
313 return FindMetaBitResult::Found { addr: cur, bit };
314 }
315 }
316 }
317 FindMetaBitResult::NotFound
318}
319
320pub fn find_last_non_zero_bit_in_metadata_bits(
322 addr: Address,
323 start_bit: u8,
324 end_bit: u8,
325) -> FindMetaBitResult {
326 if !addr.is_mapped() {
327 return FindMetaBitResult::UnmappedMetadata;
328 }
329 let byte = unsafe { addr.load::<u8>() };
330 if let Some(bit) = find_last_non_zero_bit::<u8>(byte, start_bit, end_bit) {
331 return FindMetaBitResult::Found { addr, bit };
332 }
333 FindMetaBitResult::NotFound
334}
335
336use num_traits::{CheckedShl, PrimInt};
337fn find_last_non_zero_bit<T>(value: T, start: u8, end: u8) -> Option<u8>
338where
339 T: PrimInt + CheckedShl,
340{
341 let mask = match T::one().checked_shl((end - start) as u32) {
342 Some(shl) => (shl - T::one()) << (start as u32),
343 None => T::max_value() << (start as u32),
344 };
345 let masked = value & mask;
346 if masked.is_zero() {
347 None
348 } else {
349 let leading_zeroes = masked.leading_zeros();
350 let total_bits = std::mem::size_of::<T>() * u8::BITS as usize;
351 Some(total_bits as u8 - leading_zeroes as u8 - 1)
352 }
353}
354
355pub fn find_first_non_zero_bit_in_metadata_bytes(
356 meta_start: Address,
357 meta_end: Address,
358) -> FindMetaBitResult {
359 use crate::util::constants::BYTES_IN_ADDRESS;
360
361 let mmap_granularity = MMAPPER.granularity();
362
363 let mut cursor = meta_start;
364 let mut mapped_grain = Address::ZERO;
368 while cursor < meta_end {
369 let step =
371 if cursor.is_aligned_to(BYTES_IN_ADDRESS) && cursor + BYTES_IN_ADDRESS <= meta_end {
372 BYTES_IN_ADDRESS
373 } else {
374 1
375 };
376 debug_assert!(
378 cursor >= meta_start && cursor < meta_end,
379 "Check metadata value at meta address {}, which is not in the range of [{}, {})",
380 cursor,
381 meta_start,
382 meta_end
383 );
384
385 if cursor > mapped_grain {
387 if cursor.is_mapped() {
388 mapped_grain = cursor.align_up(mmap_granularity) - 0x1;
390 } else {
391 return FindMetaBitResult::UnmappedMetadata;
392 }
393 }
394
395 if step == BYTES_IN_ADDRESS {
396 let value = unsafe { cursor.load::<usize>() };
398 if value != 0 {
399 let bit = find_first_non_zero_bit::<usize>(value, 0, usize::BITS as u8).unwrap();
400 let byte_offset = bit >> LOG_BITS_IN_BYTE;
401 let bit_offset = bit - ((byte_offset) << LOG_BITS_IN_BYTE);
402 return FindMetaBitResult::Found {
403 addr: cursor + byte_offset as usize,
404 bit: bit_offset,
405 };
406 }
407 } else {
408 let value = unsafe { cursor.load::<u8>() };
410 if let Some(bit) = find_first_non_zero_bit::<u8>(value, 0, 8) {
411 return FindMetaBitResult::Found { addr: cursor, bit };
412 }
413 }
414 cursor += step;
416 }
417 FindMetaBitResult::NotFound
418}
419
420pub fn find_first_non_zero_bit_in_metadata_bits(
421 addr: Address,
422 start_bit: u8,
423 end_bit: u8,
424) -> FindMetaBitResult {
425 if !addr.is_mapped() {
426 return FindMetaBitResult::UnmappedMetadata;
427 }
428 let byte = unsafe { addr.load::<u8>() };
429 if let Some(bit) = find_first_non_zero_bit::<u8>(byte, start_bit, end_bit) {
430 return FindMetaBitResult::Found { addr, bit };
431 }
432 FindMetaBitResult::NotFound
433}
434
435fn find_first_non_zero_bit<T>(value: T, start: u8, end: u8) -> Option<u8>
436where
437 T: PrimInt + CheckedShl,
438{
439 let mask = match T::one().checked_shl((end - start) as u32) {
440 Some(shl) => (shl - T::one()) << (start as u32),
441 None => T::max_value() << (start as u32),
442 };
443 let masked = value & mask;
444 if masked.is_zero() {
445 None
446 } else {
447 let trailing_zeroes = masked.trailing_zeros();
448 Some(trailing_zeroes as u8)
449 }
450}
451
452pub fn scan_non_zero_bits_in_metadata_bytes(
453 meta_start: Address,
454 meta_end: Address,
455 visit_bit: &mut impl FnMut(Address, BitOffset),
456) {
457 use crate::util::constants::BYTES_IN_ADDRESS;
458
459 let mut cursor = meta_start;
460 while cursor < meta_end && !cursor.is_aligned_to(BYTES_IN_ADDRESS) {
461 let byte = unsafe { cursor.load::<u8>() };
462 scan_non_zero_bits_in_metadata_word(cursor, byte as usize, visit_bit);
463 cursor += 1usize;
464 }
465
466 while cursor + BYTES_IN_ADDRESS < meta_end {
467 let word = unsafe { cursor.load::<usize>() };
468 scan_non_zero_bits_in_metadata_word(cursor, word, visit_bit);
469 cursor += BYTES_IN_ADDRESS;
470 }
471
472 while cursor < meta_end {
473 let byte = unsafe { cursor.load::<u8>() };
474 scan_non_zero_bits_in_metadata_word(cursor, byte as usize, visit_bit);
475 cursor += 1usize;
476 }
477}
478
479fn scan_non_zero_bits_in_metadata_word(
480 meta_addr: Address,
481 mut word: usize,
482 visit_bit: &mut impl FnMut(Address, BitOffset),
483) {
484 while word != 0 {
485 let bit = word.trailing_zeros();
486 visit_bit(meta_addr, bit as u8);
487 word = word & (word - 1);
488 }
489}
490
491pub fn scan_non_zero_bits_in_metadata_bits(
492 meta_addr: Address,
493 bit_start: BitOffset,
494 bit_end: BitOffset,
495 visit_bit: &mut impl FnMut(Address, BitOffset),
496) {
497 let byte = unsafe { meta_addr.load::<u8>() };
498 for bit in bit_start..bit_end {
499 if byte & (1 << bit) != 0 {
500 visit_bit(meta_addr, bit);
501 }
502 }
503}
504
505#[cfg(test)]
506mod tests {
507 use super::*;
508 use crate::util::metadata::side_metadata::*;
509
510 fn should_skip_spec_on_this_target(spec: &SideMetadataSpec) -> bool {
511 use layout::LOG_GLOBAL_SIDE_METADATA_WORST_CASE_RATIO;
512 log_data_meta_ratio(spec) < LOG_GLOBAL_SIDE_METADATA_WORST_CASE_RATIO
513 }
514
515 fn test_round_trip_conversion(spec: &SideMetadataSpec, test_data: &[Address]) {
516 if should_skip_spec_on_this_target(spec) {
517 eprintln!(
518 "Skipping {} on this target: spec ratio is outside global side metadata worst-case bound",
519 spec.name
520 );
521 return;
522 }
523
524 core_test_initialize_side_metadata();
525
526 for ref_addr in test_data {
527 let addr = *ref_addr;
528
529 {
531 assert!(addr.is_aligned_to(1 << spec.log_bytes_in_region));
532 let meta_addr = address_to_contiguous_meta_address(spec, addr);
533 let shift = meta_byte_lshift(spec, addr);
534 assert_eq!(
535 contiguous_meta_address_to_address(spec, meta_addr, shift),
536 addr
537 );
538 }
539
540 {
542 let next_addr = addr + 1usize;
543 let meta_addr = address_to_contiguous_meta_address(spec, next_addr);
544 let shift = meta_byte_lshift(spec, next_addr);
545 assert_eq!(
546 contiguous_meta_address_to_address(spec, meta_addr, shift),
547 addr
548 ); }
550 }
551 }
552
553 const TEST_ADDRESS_8B_REGION: [Address; 8] = [
554 unsafe { Address::from_usize(0x8000_0000) },
555 unsafe { Address::from_usize(0x8000_0008) },
556 unsafe { Address::from_usize(0x8000_0010) },
557 unsafe { Address::from_usize(0x8000_0018) },
558 unsafe { Address::from_usize(0x8000_0020) },
559 unsafe { Address::from_usize(0x8001_0000) },
560 unsafe { Address::from_usize(0x8001_0008) },
561 unsafe { Address::from_usize(0xd000_0000) },
562 ];
563
564 #[test]
565 fn test_contiguous_metadata_conversion_0_3() {
566 let spec = SideMetadataSpec {
567 name: "ContiguousMetadataTestSpec",
568 is_global: true,
569 offset: 0,
570 log_num_of_bits: 0,
571 log_bytes_in_region: 3,
572 };
573
574 test_round_trip_conversion(&spec, &TEST_ADDRESS_8B_REGION);
575 }
576
577 #[test]
578 fn test_contiguous_metadata_conversion_1_3() {
579 let spec = SideMetadataSpec {
580 name: "ContiguousMetadataTestSpec",
581 is_global: true,
582 offset: 0,
583 log_num_of_bits: 1,
584 log_bytes_in_region: 3,
585 };
586
587 test_round_trip_conversion(&spec, &TEST_ADDRESS_8B_REGION);
588 }
589
590 #[test]
591 fn test_contiguous_metadata_conversion_4_3() {
592 let spec = SideMetadataSpec {
593 name: "ContiguousMetadataTestSpec",
594 is_global: true,
595 offset: 0,
596 log_num_of_bits: 4,
597 log_bytes_in_region: 3,
598 };
599
600 test_round_trip_conversion(&spec, &TEST_ADDRESS_8B_REGION);
601 }
602
603 #[test]
604 fn test_contiguous_metadata_conversion_5_3() {
605 let spec = SideMetadataSpec {
606 name: "ContiguousMetadataTestSpec",
607 is_global: true,
608 offset: 0,
609 log_num_of_bits: 5,
610 log_bytes_in_region: 3,
611 };
612
613 test_round_trip_conversion(&spec, &TEST_ADDRESS_8B_REGION);
614 }
615
616 const TEST_ADDRESS_4KB_REGION: [Address; 8] = [
617 unsafe { Address::from_usize(0x8000_0000) },
618 unsafe { Address::from_usize(0x8000_1000) },
619 unsafe { Address::from_usize(0x8000_2000) },
620 unsafe { Address::from_usize(0x8000_3000) },
621 unsafe { Address::from_usize(0x8000_4000) },
622 unsafe { Address::from_usize(0x8001_0000) },
623 unsafe { Address::from_usize(0x8001_1000) },
624 unsafe { Address::from_usize(0xd000_0000) },
625 ];
626
627 #[test]
628 fn test_contiguous_metadata_conversion_0_12() {
629 let spec = SideMetadataSpec {
630 name: "ContiguousMetadataTestSpec",
631 is_global: true,
632 offset: 0,
633 log_num_of_bits: 0,
634 log_bytes_in_region: 12, };
636
637 test_round_trip_conversion(&spec, &TEST_ADDRESS_4KB_REGION);
638 }
639
640 #[test]
641 fn test_find_last_non_zero_bit_in_u8() {
642 use super::find_last_non_zero_bit;
643 let bit = find_last_non_zero_bit::<u8>(0b100101, 0, 1);
644 assert_eq!(bit, Some(0));
645
646 let bit = find_last_non_zero_bit::<u8>(0b100101, 0, 3);
647 assert_eq!(bit, Some(2));
648
649 let bit = find_last_non_zero_bit::<u8>(0b100101, 0, 8);
650 assert_eq!(bit, Some(5));
651
652 let bit = find_last_non_zero_bit::<u8>(0b0, 0, 1);
653 assert_eq!(bit, None);
654 }
655
656 #[test]
657 fn test_align_metadata_address() {
658 let create_spec = |log_num_of_bits: usize| SideMetadataSpec {
659 name: "AlignMetadataBitTestSpec",
660 is_global: true,
661 offset: 0,
662 log_num_of_bits,
663 log_bytes_in_region: 3,
664 };
665
666 const ADDR_1000: Address = unsafe { Address::from_usize(0x1000) };
667 const ADDR_1001: Address = unsafe { Address::from_usize(0x1001) };
668 const ADDR_1002: Address = unsafe { Address::from_usize(0x1002) };
669 const ADDR_1003: Address = unsafe { Address::from_usize(0x1003) };
670 const ADDR_1004: Address = unsafe { Address::from_usize(0x1004) };
671 const ADDR_1005: Address = unsafe { Address::from_usize(0x1005) };
672 const ADDR_1006: Address = unsafe { Address::from_usize(0x1006) };
673 const ADDR_1007: Address = unsafe { Address::from_usize(0x1007) };
674 const ADDR_1008: Address = unsafe { Address::from_usize(0x1008) };
675 const ADDR_1009: Address = unsafe { Address::from_usize(0x1009) };
676
677 let metadata_2bits = create_spec(1);
678 assert_eq!(
679 align_metadata_address(&metadata_2bits, ADDR_1000, 0),
680 (ADDR_1000, 0)
681 );
682 assert_eq!(
683 align_metadata_address(&metadata_2bits, ADDR_1000, 1),
684 (ADDR_1000, 0)
685 );
686 assert_eq!(
687 align_metadata_address(&metadata_2bits, ADDR_1000, 2),
688 (ADDR_1000, 2)
689 );
690 assert_eq!(
691 align_metadata_address(&metadata_2bits, ADDR_1000, 3),
692 (ADDR_1000, 2)
693 );
694 assert_eq!(
695 align_metadata_address(&metadata_2bits, ADDR_1000, 4),
696 (ADDR_1000, 4)
697 );
698 assert_eq!(
699 align_metadata_address(&metadata_2bits, ADDR_1000, 5),
700 (ADDR_1000, 4)
701 );
702 assert_eq!(
703 align_metadata_address(&metadata_2bits, ADDR_1000, 6),
704 (ADDR_1000, 6)
705 );
706 assert_eq!(
707 align_metadata_address(&metadata_2bits, ADDR_1000, 7),
708 (ADDR_1000, 6)
709 );
710
711 let metadata_4bits = create_spec(2);
712 assert_eq!(
713 align_metadata_address(&metadata_4bits, ADDR_1000, 0),
714 (ADDR_1000, 0)
715 );
716 assert_eq!(
717 align_metadata_address(&metadata_4bits, ADDR_1000, 1),
718 (ADDR_1000, 0)
719 );
720 assert_eq!(
721 align_metadata_address(&metadata_4bits, ADDR_1000, 2),
722 (ADDR_1000, 0)
723 );
724 assert_eq!(
725 align_metadata_address(&metadata_4bits, ADDR_1000, 3),
726 (ADDR_1000, 0)
727 );
728 assert_eq!(
729 align_metadata_address(&metadata_4bits, ADDR_1000, 4),
730 (ADDR_1000, 4)
731 );
732 assert_eq!(
733 align_metadata_address(&metadata_4bits, ADDR_1000, 5),
734 (ADDR_1000, 4)
735 );
736 assert_eq!(
737 align_metadata_address(&metadata_4bits, ADDR_1000, 6),
738 (ADDR_1000, 4)
739 );
740 assert_eq!(
741 align_metadata_address(&metadata_4bits, ADDR_1000, 7),
742 (ADDR_1000, 4)
743 );
744
745 let metadata_8bits = create_spec(3);
746 assert_eq!(
747 align_metadata_address(&metadata_8bits, ADDR_1000, 0),
748 (ADDR_1000, 0)
749 );
750 assert_eq!(
751 align_metadata_address(&metadata_8bits, ADDR_1000, 1),
752 (ADDR_1000, 0)
753 );
754 assert_eq!(
755 align_metadata_address(&metadata_8bits, ADDR_1000, 2),
756 (ADDR_1000, 0)
757 );
758 assert_eq!(
759 align_metadata_address(&metadata_8bits, ADDR_1000, 3),
760 (ADDR_1000, 0)
761 );
762 assert_eq!(
763 align_metadata_address(&metadata_8bits, ADDR_1000, 4),
764 (ADDR_1000, 0)
765 );
766 assert_eq!(
767 align_metadata_address(&metadata_8bits, ADDR_1000, 5),
768 (ADDR_1000, 0)
769 );
770 assert_eq!(
771 align_metadata_address(&metadata_8bits, ADDR_1000, 6),
772 (ADDR_1000, 0)
773 );
774 assert_eq!(
775 align_metadata_address(&metadata_8bits, ADDR_1000, 7),
776 (ADDR_1000, 0)
777 );
778
779 let metadata_16bits = create_spec(4);
780 assert_eq!(
781 align_metadata_address(&metadata_16bits, ADDR_1000, 0),
782 (ADDR_1000, 0)
783 );
784 assert_eq!(
785 align_metadata_address(&metadata_16bits, ADDR_1000, 1),
786 (ADDR_1000, 0)
787 );
788 assert_eq!(
789 align_metadata_address(&metadata_16bits, ADDR_1000, 2),
790 (ADDR_1000, 0)
791 );
792 assert_eq!(
793 align_metadata_address(&metadata_16bits, ADDR_1000, 3),
794 (ADDR_1000, 0)
795 );
796 assert_eq!(
797 align_metadata_address(&metadata_16bits, ADDR_1000, 4),
798 (ADDR_1000, 0)
799 );
800 assert_eq!(
801 align_metadata_address(&metadata_16bits, ADDR_1000, 5),
802 (ADDR_1000, 0)
803 );
804 assert_eq!(
805 align_metadata_address(&metadata_16bits, ADDR_1000, 6),
806 (ADDR_1000, 0)
807 );
808 assert_eq!(
809 align_metadata_address(&metadata_16bits, ADDR_1000, 7),
810 (ADDR_1000, 0)
811 );
812 assert_eq!(
813 align_metadata_address(&metadata_16bits, ADDR_1001, 0),
814 (ADDR_1000, 0)
815 );
816 assert_eq!(
817 align_metadata_address(&metadata_16bits, ADDR_1001, 1),
818 (ADDR_1000, 0)
819 );
820 assert_eq!(
821 align_metadata_address(&metadata_16bits, ADDR_1001, 2),
822 (ADDR_1000, 0)
823 );
824 assert_eq!(
825 align_metadata_address(&metadata_16bits, ADDR_1001, 3),
826 (ADDR_1000, 0)
827 );
828 assert_eq!(
829 align_metadata_address(&metadata_16bits, ADDR_1001, 4),
830 (ADDR_1000, 0)
831 );
832 assert_eq!(
833 align_metadata_address(&metadata_16bits, ADDR_1001, 5),
834 (ADDR_1000, 0)
835 );
836 assert_eq!(
837 align_metadata_address(&metadata_16bits, ADDR_1001, 6),
838 (ADDR_1000, 0)
839 );
840 assert_eq!(
841 align_metadata_address(&metadata_16bits, ADDR_1001, 7),
842 (ADDR_1000, 0)
843 );
844 }
845}