mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-07-27 04:13:53 -06:00

The bindgen supports `static inline` function binding since v0.64.0 as an experimental feature (`--wrap-static-fns`), and stabilizes it after v0.70.0. But the oldest version of bindgen supported by QEMU is v0.60.1, so there's no way to generate the binding for deposit64() which is `static inline` (in include/qemu/bitops.h). Instead, implement it by hand in Rust and make it available for all unsigned types through an IntegerExt trait. Since it only involves bit operations, the Rust version of the code is almost identical to the original C version, but it applies to more types than just u64. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> Co-authored-by: Zhao Liu <zhao1.liu@intel.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
119 lines
3.1 KiB
Rust
119 lines
3.1 KiB
Rust
// Copyright (C) 2024 Intel Corporation.
|
|
// Author(s): Zhao Liu <zhai1.liu@intel.com>
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
//! This module provides bit operation extensions to integer types.
|
|
//! It is usually included via the `qemu_api` prelude.
|
|
|
|
use std::ops::{
|
|
Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
|
|
Mul, MulAssign, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign,
|
|
};
|
|
|
|
/// Trait for extensions to integer types
|
|
pub trait IntegerExt:
|
|
Add<Self, Output = Self> + AddAssign<Self> +
|
|
BitAnd<Self, Output = Self> + BitAndAssign<Self> +
|
|
BitOr<Self, Output = Self> + BitOrAssign<Self> +
|
|
BitXor<Self, Output = Self> + BitXorAssign<Self> +
|
|
Copy +
|
|
Div<Self, Output = Self> + DivAssign<Self> +
|
|
Eq +
|
|
Mul<Self, Output = Self> + MulAssign<Self> +
|
|
Not<Output = Self> + Ord + PartialOrd +
|
|
Rem<Self, Output = Self> + RemAssign<Self> +
|
|
Shl<Self, Output = Self> + ShlAssign<Self> +
|
|
Shl<u32, Output = Self> + ShlAssign<u32> + // add more as needed
|
|
Shr<Self, Output = Self> + ShrAssign<Self> +
|
|
Shr<u32, Output = Self> + ShrAssign<u32> // add more as needed
|
|
{
|
|
const BITS: u32;
|
|
const MAX: Self;
|
|
const MIN: Self;
|
|
const ONE: Self;
|
|
const ZERO: Self;
|
|
|
|
#[inline]
|
|
#[must_use]
|
|
fn bit(start: u32) -> Self
|
|
{
|
|
debug_assert!(start < Self::BITS);
|
|
|
|
Self::ONE << start
|
|
}
|
|
|
|
#[inline]
|
|
#[must_use]
|
|
fn mask(start: u32, length: u32) -> Self
|
|
{
|
|
/* FIXME: Implement a more elegant check with error handling support? */
|
|
debug_assert!(start < Self::BITS && length > 0 && length <= Self::BITS - start);
|
|
|
|
(Self::MAX >> (Self::BITS - length)) << start
|
|
}
|
|
|
|
#[inline]
|
|
#[must_use]
|
|
fn deposit<U: IntegerExt>(self, start: u32, length: u32,
|
|
fieldval: U) -> Self
|
|
where Self: From<U>
|
|
{
|
|
debug_assert!(length <= U::BITS);
|
|
|
|
let mask = Self::mask(start, length);
|
|
(self & !mask) | ((Self::from(fieldval) << start) & mask)
|
|
}
|
|
|
|
#[inline]
|
|
#[must_use]
|
|
fn extract(self, start: u32, length: u32) -> Self
|
|
{
|
|
let mask = Self::mask(start, length);
|
|
(self & mask) >> start
|
|
}
|
|
}
|
|
|
|
macro_rules! impl_num_ext {
|
|
($type:ty) => {
|
|
impl IntegerExt for $type {
|
|
const BITS: u32 = <$type>::BITS;
|
|
const MAX: Self = <$type>::MAX;
|
|
const MIN: Self = <$type>::MIN;
|
|
const ONE: Self = 1;
|
|
const ZERO: Self = 0;
|
|
}
|
|
};
|
|
}
|
|
|
|
impl_num_ext!(u8);
|
|
impl_num_ext!(u16);
|
|
impl_num_ext!(u32);
|
|
impl_num_ext!(u64);
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_deposit() {
|
|
assert_eq!(15u32.deposit(8, 8, 1u32), 256 + 15);
|
|
assert_eq!(15u32.deposit(8, 1, 255u8), 256 + 15);
|
|
}
|
|
|
|
#[test]
|
|
fn test_extract() {
|
|
assert_eq!(15u32.extract(2, 4), 3);
|
|
}
|
|
|
|
#[test]
|
|
fn test_bit() {
|
|
assert_eq!(u8::bit(7), 128);
|
|
assert_eq!(u32::bit(16), 0x10000);
|
|
}
|
|
|
|
#[test]
|
|
fn test_mask() {
|
|
assert_eq!(u8::mask(7, 1), 128);
|
|
assert_eq!(u32::mask(8, 8), 0xff00);
|
|
}
|
|
}
|