Address Operations¶
+Addresses¶
+-
+
-
+template<typename EXTENT>
class address_slice¶
+ The correctness of address operations is critical to the correctness of ChampSim.
+This class is a strong type for addresses to prevent bugs that would result from unchecked operations on raw integers. The primary benefit is this: Most address operation bugs are compiler errors. Those that are not are usually runtime exceptions. If you need to manipulate the bits of an address, you can, but you must explicitly enter an unsafe mode.
+This class is a generalization of a subset of address bits. Implicit conversions between address slices of different extents are compile-time errors, providing a measure of safety. New slices must be explicitly constructed.
+++// LOG2_PAGE_SIZE = 12 +// LOG2_BLOCK_SIZE = 6 +address full_addr{0xffff'ffff}; +block_number block{full_addr}; // 0xffff'ffc0 +page_number page{full_addr}; // 0xffff'f000 +
All address slices can take their extent as a constructor parameter.
+++address_slice st_full_addr{static_extent<64_b,0_b>{},0xffff'ffff}; +address_slice st_block{static_extent<64_b, champsim::data::bits{LOG2_BLOCK_SIZE}>{}, st_full_addr}; // 0xffff'ffc0 +address_slice st_page{static_extent<64_b, champsim::data::bits{LOG2_PAGE_SIZE}>{}, st_full_addr}; // 0xffff'f000 + +address_slice dyn_full_addr{dynamic_extent{64_b,0_b},0xffff'ffff}; +address_slice dyn_block{dynamic_extent{64_b, champsim::data::bits{LOG2_BLOCK_SIZE}}, dyn_full_addr}; // 0xffff'ffc0 +address_slice dyn_page{dynamic_extent{64_b, champsim::data::bits{LOG2_PAGE_SIZE}}, dyn_full_addr}; // 0xffff'f000 +
For static extents, it can be useful to explicitly specify the template parameter.
+++address_slice<static_extent<64_b,0_b>> st_full_addr{0xffff'ffff}; +address_slice<static_extent<champsim::data::bits{LOG2_BLOCK_SIZE}, 0_b>> st_block{st_full_addr}; // 0x3f +address_slice<static_extent<champsim::data::bits{LOG2_PAGE_SIZE}, 0_b>> st_page{st_full_addr}; // 0xfff +
The address slices have a constructor that accepts a uint64_t. No bit shifting is performed in these constructors. The argument is assumed to be in the domain of the slice.
+++champsim::block_number block{0xffff}; // 0x003f'ffc0 +
Relative slicing is possible with member functions:
+++address_slice<static_extent<24_b,12_b>>::slice(static_extent<8_b,4_b>{}) -> address_slice<static_extent<20_b,16_b>> +address_slice<static_extent<24_b,12_b>>::slice<8_b,4_b>() -> address_slice<static_extent<20_b,16_b>> +address_slice<static_extent<24_b,12_b>>::slice_upper<4_b>() -> address_slice<static_extent<24_b,16_b>> +address_slice<static_extent<24_b,12_b>>::slice_lower<8_b>() -> address_slice<static_extent<20_b,12_b>> +
The offset between two addresses can be found with
+++auto champsim::offset(champsim::address base, champsim::address other) -> champsim::address::difference_type +auto champsim::uoffset(champsim::address base, champsim::address other) -> std::make_unsigned_t<champsim::address::difference_type> +
The function is a template, so any address slice is accepted, but the two arguments must be of the same type. For the first function, the return type is signed and the conversion is safe against overflows, where it will throw an exception. For the second function, the return type is unsigned and the ‘other’ argument must succeed ‘base’, or the function will throw an exception.
+Address slices also support addition and subtraction with signed integers. The arguments to this arithmetic are in the domain of the type.
+++champsim::block_number block{0xffff}; // 0x003f'ffc0 +block += 1; // 0x0040'0000 +
Two or more slices can be spliced together. Later arguments takes priority over the first, and the result type has an extent that is a superset of all slices.
+++champsim::splice(champsim::page_number{0xaaa}, champsim::page_offset{0xbbb}) == champsim::address{0xaaabbb}; +
Sometimes, it is necessary to directly manipulate the bits of an address in a way that these strong types do not allow. Additionally, sometimes slices must be used as array indices. In those cases, the address_slice<>::to<T>() function performs a checked cast to the type.
+++champsim::address addr{0xffff'ffff}; +class Foo {}; +std::array<Foo, 256> foos = {}; +auto the_foo = foos.at(addr.slice_lower<8_b>().to<std::size_t>()); +
-
+
- Template Parameters: +
EXTENT – One of
+champsim::static_extent<>
,champsim::dynamic_extent
, or one of the page- or block-sized extents.
+
++Public Types
+ + +-
+
-
+using underlying_type = uint64_t¶
The underlying representation of the address.
+
-
+
-
+using difference_type = std::make_signed_t<underlying_type>¶
The type of an offset between two addresses.
+
++Public Functions
+-
+
-
+inline constexpr address_slice() noexcept(is_static)¶
Default-initialize the slice. This constructor is invalid for dynamically-sized extents.
+
-
+
-
+inline explicit constexpr address_slice(underlying_type val) noexcept(is_static)¶
Initialize the slice with the given raw value. This constructor is invalid for dynamically-sized extents.
+
-
+
-
+template<typename OTHER_EXT>
inline explicit constexpr address_slice(const address_slice<OTHER_EXT> &val) noexcept(is_static)¶
+ Initialize the slice with the given slice, shifting and masking if necessary. If this extent is dynamic, it will have the same bounds as the given slice. If the conversion is a widening, the widened bits will be 0.
+
-
+
-
+template<typename OTHER_EXT>
inline constexpr address_slice(extent_type ext, const address_slice<OTHER_EXT> &val) noexcept(is_static)¶
+ Initialize the slice with the given slice, shifting and masking if necessary. The extent type can be deduced from the first argument. If the conversion is a widening, the widened bits will be 0.
+
-
+
-
+inline constexpr address_slice(extent_type ext, underlying_type val) noexcept(is_static)¶
Initialize the slice with the given value. The extent type can be deduced from the first argument. If the conversion is a widening, the widened bits will be 0.
+
-
+
-
+template<typename T>
inline constexpr T to() const¶
+ Unwrap the value of this slice as a raw integer value.
+
-
+
-
+inline constexpr bool operator==(self_type other) const noexcept(is_static)¶
Compare with another address slice for equality.
+-
+
- Throws: +
std::invalid_argument – If the extents do not match
+
+
-
+
-
+inline constexpr bool operator<(self_type other) const noexcept(is_static)¶
Compare with another address slice for ordering.
+-
+
- Throws: +
std::invalid_argument – If the extents do not match
+
+
-
+
-
+inline constexpr bool operator!=(self_type other) const noexcept(is_static)¶
Compare with another address slice for inequality.
+-
+
- Throws: +
std::invalid_argument – If the extents do not match
+
+
-
+
-
+inline constexpr bool operator<=(self_type other) const noexcept(is_static)¶
Compare with another address slice for ordering.
+-
+
- Throws: +
std::invalid_argument – If the extents do not match
+
+
-
+
-
+inline constexpr bool operator>(self_type other) const noexcept(is_static)¶
Compare with another address slice for ordering.
+-
+
- Throws: +
std::invalid_argument – If the extents do not match
+
+
-
+
-
+inline constexpr bool operator>=(self_type other) const noexcept(is_static)¶
Compare with another address slice for ordering.
+-
+
- Throws: +
std::invalid_argument – If the extents do not match
+
+
-
+
-
+inline constexpr self_type &operator+=(difference_type delta)¶
Increment the slice in place by the given amount. The delta is interpreted in the domain of the slice. That is, the delta need not be scaled by
+1 << slice.lower_extent()
.
-
+
-
+inline constexpr self_type &operator+=(champsim::data::bytes delta)¶
Increment the slice in place by the given amount. The delta is interpreted in the domain of the slice. That is, the delta need not be scaled by
+1 << slice.lower_extent()
.
-
+
-
+inline constexpr self_type operator+(difference_type delta) const¶
Increment the slice by the given amount. The delta is interpreted in the domain of the slice. That is, the delta need not be scaled by
+1 << slice.lower_extent()
.
-
+
-
+inline constexpr self_type operator+(champsim::data::bytes delta) const¶
Increment the slice by the given amount. The delta is interpreted in the domain of the slice. That is, the delta need not be scaled by
+1 << slice.lower_extent()
.
-
+
-
+inline constexpr self_type &operator-=(difference_type delta)¶
Decrement the slice in place by the given amount. The delta is interpreted in the domain of the slice. That is, the delta need not be scaled by
+1 << slice.lower_extent()
.
-
+
-
+inline constexpr self_type &operator-=(champsim::data::bytes delta)¶
Decrement the slice in place by the given amount. The delta is interpreted in the domain of the slice. That is, the delta need not be scaled by
+1 << slice.lower_extent()
.
-
+
-
+inline constexpr self_type operator-(difference_type delta) const¶
Decrement the slice by the given amount. The delta is interpreted in the domain of the slice. That is, the delta need not be scaled by
+1 << slice.lower_extent()
.
-
+
-
+inline constexpr self_type operator-(champsim::data::bytes delta) const¶
Decrement the slice by the given amount. The delta is interpreted in the domain of the slice. That is, the delta need not be scaled by
+1 << slice.lower_extent()
.
-
+
-
+inline constexpr self_type &operator++()¶
Increment the slice by one.
+
-
+
-
+inline constexpr self_type operator++(int)¶
Increment the slice by one.
+
-
+
-
+inline constexpr self_type &operator--()¶
Decrement the slice by one.
+
-
+
-
+inline constexpr self_type operator--(int)¶
Decrement the slice by one.
+
-
+
-
+template<typename SUB_EXTENT>
inline auto slice(SUB_EXTENT subextent) const noexcept(is_static && detail::extent_is_static<SUB_EXTENT>)¶
+ Perform a slice on this address. The given extent should be relative to this slice’s extent. If either this extent or the subextent are runtime-sized, the result will have a runtime-sized extent. Otherwise, the extent will be statically-sized.
+
-
+
-
+template<champsim::data::bits new_upper, champsim::data::bits new_lower>
inline auto slice() const noexcept¶
+ Perform a slice on this address. The given extent should be relative to this slice’s extent. This is a synonym for
+slice(static_extent<new_upper, new_lower>{})
.
-
+
-
+template<champsim::data::bits new_lower>
inline auto slice_upper() const noexcept¶
+ Slice the upper bits, ending with the given bit relative to the lower extent of this. If this slice is statically-sized, the result will be statically-sized.
+
-
+
-
+template<champsim::data::bits new_upper>
inline auto slice_lower() const noexcept¶
+ Slice the lower bits, ending with the given bit relative to the lower extent of this. If this slice is statically-sized, the result will be statically-sized.
+
-
+
-
+inline auto slice_upper(champsim::data::bits new_lower) const¶
Slice the upper bits, ending with the given bit relative to the lower extent of this. The result of this will always be runtime-sized.
+
-
+
-
+inline auto slice_lower(champsim::data::bits new_upper) const¶
Slice the lower bits, ending with the given bit relative to the lower extent of this. The result of this will always be runtime-sized.
+
-
+
-
+template<champsim::data::bits split_loc>
inline auto split() const¶
+ Split the slice into an upper and lower slice.
+
-
+
-
+inline auto split(champsim::data::bits split_loc) const¶
Split the slice into an upper and lower slice.
+
-
+
-
+inline constexpr auto upper_extent() const noexcept¶
Get the upper portion of the extent.
+
-
+
-
+inline constexpr auto lower_extent() const noexcept¶
Get the lower portion of the extent.
+
++Public Static Attributes
+-
+
-
+static constexpr champsim::data::bits bits = {std::numeric_limits<underlying_type>::digits}¶
The maximum width of any address slice. This is not the width of this slice, which can be found by
+slice.upper_extent() - slice.lower_extent()
.
-
+
-
+template<typename Extent>
constexpr auto champsim::offset(address_slice<Extent> base, address_slice<Extent> other) -> typename address_slice<Extent>::difference_type¶
+ Find the offset between two slices with the same types.
+-
+
- Throws: +
overflow_error – if the difference cannot be represented in the difference type
+
+
-
+
-
+template<typename Extent>
constexpr auto champsim::uoffset(address_slice<Extent> base, address_slice<Extent> other) -> std::make_unsigned_t<typename address_slice<Extent>::difference_type>¶
+ Find the offset between two slices with the same types, where the first element must be less than or equal to than the second. The return type of this function is unsigned.
+-
+
- Throws: +
overflow_error – if the difference cannot be represented in the difference type
+
+
-
+
-
+template<typename ...Extents>
constexpr auto champsim::splice(address_slice<Extents>... slices)¶
+ Join address slices together. Later slices will overwrite bits from earlier slices. The extent of the returned slice is the superset of all slices. If all of the slices are statically-sized, the result will be statically-sized as well.
+
Convenience typedefs¶
+Champsim provides five specializations of an address slice in inc/champsim.h
-
+
-
+using champsim::address = address_slice<static_extent<champsim::data::bits{std::numeric_limits<uint64_t>::digits}, champsim::data::bits{}>>¶
Convenience definitions for commmon address slices
+
-
+
-
+using champsim::page_number = address_slice<page_number_extent>¶
-
+
-
+using champsim::page_offset = address_slice<page_offset_extent>¶
-
+
-
+using champsim::block_number = address_slice<block_number_extent>¶
-
+
-
+using champsim::block_offset = address_slice<block_offset_extent>¶
Extents¶
+-
+
-
+template<champsim::data::bits UP, champsim::data::bits LOW>
struct static_extent¶
+ An extent with compile-time size
+ +
-
+
-
+struct dynamic_extent¶
An extent with runtime size
+Subclassed by champsim::block_number_extent, champsim::block_offset_extent, champsim::page_number_extent, champsim::page_offset_extent
+ + +
-
+
-
+struct page_number_extent : public champsim::dynamic_extent¶
An extent that is always the size of a page number
+++Public Functions
+-
+
-
+page_number_extent()¶
This extent can only be default-initialized. It will have
+upper == champsim::address::bits
andlower == LOG2_PAGE_SIZE
.
-
+page_number_extent()¶
-
+
-
+struct page_offset_extent : public champsim::dynamic_extent¶
An extent that is always the size of a page offset
+++Public Functions
+-
+
-
+page_offset_extent()¶
This extent can only be default-initialized. It will have
+upper == LOG2_PAGE_SIZE
andlower == 0
.
-
+page_offset_extent()¶
-
+
-
+struct block_number_extent : public champsim::dynamic_extent¶
An extent that is always the size of a block number
+++Public Functions
+-
+
-
+block_number_extent()¶
This extent can only be default-initialized. It will have
+upper == champsim::address::bits
andlower == LOG2_BLOCK_SIZE
.
-
+block_number_extent()¶
-
+
-
+struct block_offset_extent : public champsim::dynamic_extent¶
An extent that is always the size of a block offset
+++Public Functions
+-
+
-
+block_offset_extent()¶
This extent can only be default-initialized. It will have
+upper == LOG2_BLOCK_SIZE
andlower == 0
.
-
+block_offset_extent()¶