From ee93f48729e0cd7a2ba79ea9d2a3b13a3bbe5a40 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 14 Oct 2025 23:30:12 +0200 Subject: [PATCH] core:math/bits: Finish docs, add `bitfield_extract` + `bitfield_insert` test. --- core/math/bits/bits.odin | 950 +++++++++++++++++- tests/core/math/bits/test_core_math_bits.odin | 23 + 2 files changed, 924 insertions(+), 49 deletions(-) diff --git a/core/math/bits/bits.odin b/core/math/bits/bits.odin index 1edafebf4..1e8d765dd 100644 --- a/core/math/bits/bits.odin +++ b/core/math/bits/bits.odin @@ -234,57 +234,261 @@ rotate_left :: proc "contextless" (x: uint, k: int) -> uint { return x << s | x >> (n-s) } +/* +Returns unsigned integer `i` + +NOTE: A byte has no endianness, so `from_be_u8` exists to be complementary to `from_be_*`. + +Inputs: +- i: The unsigned integer + +Returns: +- res: `i` +*/ @(require_results) from_be_u8 :: proc "contextless" (i: u8) -> u8 { return i } + +/* +Returns unsigned integer `i`, byte-swapped if we're on a little endian target. + +Inputs: +- i: The unsigned integer + +Returns: +- res: `i`, optionally byte-swapped +*/ @(require_results) from_be_u16 :: proc "contextless" (i: u16) -> u16 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } } + +/* +Returns unsigned integer `i`, byte-swapped if we're on a little endian target. + +Inputs: +- i: The unsigned integer + +Returns: +- res: `i`, optionally byte-swapped +*/ @(require_results) from_be_u32 :: proc "contextless" (i: u32) -> u32 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } } + +/* +Returns unsigned integer `i`, byte-swapped if we're on a little endian target. + +Inputs: +- i: The unsigned integer + +Returns: +- res: `i`, optionally byte-swapped +*/ @(require_results) from_be_u64 :: proc "contextless" (i: u64) -> u64 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } } + +/* +Returns unsigned integer `i`, byte-swapped if we're on a little endian target. + +Inputs: +- i: The unsigned integer + +Returns: +- res: `i`, optionally byte-swapped +*/ @(require_results) from_be_uint :: proc "contextless" (i: uint) -> uint { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } } +/* +Returns unsigned integer `i` + +NOTE: A byte has no endianness, so `from_le_u8` exists to be complementary to `from_le_*`. + +Inputs: +- i: The unsigned integer + +Returns: +- res: `i` +*/ @(require_results) from_le_u8 :: proc "contextless" (i: u8) -> u8 { return i } + +/* +Returns unsigned integer `i`, byte-swapped if we're on a big endian target. + +Inputs: +- i: The unsigned integer + +Returns: +- res: `i`, optionally byte-swapped +*/ @(require_results) from_le_u16 :: proc "contextless" (i: u16) -> u16 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } } + +/* +Returns unsigned integer `i`, byte-swapped if we're on a big endian target. + +Inputs: +- i: The unsigned integer + +Returns: +- res: `i`, optionally byte-swapped +*/ @(require_results) from_le_u32 :: proc "contextless" (i: u32) -> u32 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } } + +/* +Returns unsigned integer `i`, byte-swapped if we're on a big endian target. + +Inputs: +- i: The unsigned integer + +Returns: +- res: `i`, optionally byte-swapped +*/ @(require_results) from_le_u64 :: proc "contextless" (i: u64) -> u64 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } } + +/* +Returns unsigned integer `i`, byte-swapped if we're on a big endian target. + +Inputs: +- i: The unsigned integer + +Returns: +- res: `i`, optionally byte-swapped +*/ @(require_results) from_le_uint :: proc "contextless" (i: uint) -> uint { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } } +/* +Returns unsigned integer `i` + +NOTE: A byte has no endianness, so `to_be_u8` exists to be complementary to `to_be_*`. + +Inputs: +- i: The unsigned integer + +Returns: +- res: `i` +*/ @(require_results) to_be_u8 :: proc "contextless" (i: u8) -> u8 { return i } @(require_results) + +/* +Returns unsigned integer `i`, byte-swapped if we're on a little endian target. + +Inputs: +- i: The unsigned integer + +Returns: +- res: `i`, optionally byte-swapped +*/ to_be_u16 :: proc "contextless" (i: u16) -> u16 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } } + +/* +Returns unsigned integer `i`, byte-swapped if we're on a little endian target. + +Inputs: +- i: The unsigned integer + +Returns: +- res: `i`, optionally byte-swapped +*/ @(require_results) to_be_u32 :: proc "contextless" (i: u32) -> u32 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } } + +/* +Returns unsigned integer `i`, byte-swapped if we're on a little endian target. + +Inputs: +- i: The unsigned integer + +Returns: +- res: `i`, optionally byte-swapped +*/ @(require_results) to_be_u64 :: proc "contextless" (i: u64) -> u64 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } } + +/* +Returns unsigned integer `i`, byte-swapped if we're on a little endian target. + +Inputs: +- i: The unsigned integer + +Returns: +- res: `i`, optionally byte-swapped +*/ @(require_results) to_be_uint :: proc "contextless" (i: uint) -> uint { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } } +/* +Returns unsigned integer `i` +NOTE: A byte has no endianness, so `to_le_u8` exists to be complementary to `to_le_*`. + +Inputs: +- i: The unsigned integer + +Returns: +- res: `i` +*/ @(require_results) to_le_u8 :: proc "contextless" (i: u8) -> u8 { return i } + +/* +Returns unsigned integer `i`, byte-swapped if we're on a big endian target. + +Inputs: +- i: The unsigned integer + +Returns: +- res: `i`, optionally byte-swapped +*/ @(require_results) to_le_u16 :: proc "contextless" (i: u16) -> u16 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } } + +/* +Returns unsigned integer `i`, byte-swapped if we're on a big endian target. + +Inputs: +- i: The unsigned integer + +Returns: +- res: `i`, optionally byte-swapped +*/ @(require_results) to_le_u32 :: proc "contextless" (i: u32) -> u32 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } } + +/* +Returns unsigned integer `i`, byte-swapped if we're on a big endian target. + +Inputs: +- i: The unsigned integer + +Returns: +- res: `i`, optionally byte-swapped +*/ @(require_results) to_le_u64 :: proc "contextless" (i: u64) -> u64 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } } + +/* +Returns unsigned integer `i`, byte-swapped if we're on a big endian target. + +Inputs: +- i: The unsigned integer + +Returns: +- res: `i`, optionally byte-swapped +*/ @(require_results) to_le_uint :: proc "contextless" (i: uint) -> uint { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } } - - +// returns the minimum number of bits required to represent x @(require_results) len_u8 :: proc "contextless" (x: u8) -> int { return int(len_u8_table[x]) } + +// returns the minimum number of bits required to represent x @(require_results) len_u16 :: proc "contextless" (x: u16) -> (n: int) { x := x @@ -294,6 +498,8 @@ len_u16 :: proc "contextless" (x: u16) -> (n: int) { } return n + int(len_u8_table[x]) } + +// returns the minimum number of bits required to represent x @(require_results) len_u32 :: proc "contextless" (x: u32) -> (n: int) { x := x @@ -307,6 +513,8 @@ len_u32 :: proc "contextless" (x: u32) -> (n: int) { } return n + int(len_u8_table[x]) } + +// returns the minimum number of bits required to represent x @(require_results) len_u64 :: proc "contextless" (x: u64) -> (n: int) { x := x @@ -324,6 +532,8 @@ len_u64 :: proc "contextless" (x: u64) -> (n: int) { } return n + int(len_u8_table[x]) } + +// returns the minimum number of bits required to represent x @(require_results) len_uint :: proc "contextless" (x: uint) -> (n: int) { when size_of(uint) == size_of(u64) { @@ -336,23 +546,60 @@ len_uint :: proc "contextless" (x: uint) -> (n: int) { // returns the minimum number of bits required to represent x len :: proc{len_u8, len_u16, len_u32, len_u64, len_uint} +/* +Add with carry +Inputs: +- x: The unsigned integer +- y: Another unsigned integer +- carry: Carry in + +Returns: +- sum: The sum +- carry_out: Carry out +*/ @(require_results) add_u32 :: proc "contextless" (x, y, carry: u32) -> (sum, carry_out: u32) { tmp_carry, tmp_carry2: bool - sum, tmp_carry = intrinsics.overflow_add(x, y) + sum, tmp_carry = intrinsics.overflow_add(x, y) sum, tmp_carry2 = intrinsics.overflow_add(sum, carry) carry_out = u32(tmp_carry | tmp_carry2) return } + +/* +Add with carry + +Inputs: +- x: The unsigned integer +- y: Another unsigned integer +- carry: Carry in + +Returns: +- sum: The sum +- carry_out: Carry out +*/ @(require_results) add_u64 :: proc "contextless" (x, y, carry: u64) -> (sum, carry_out: u64) { tmp_carry, tmp_carry2: bool - sum, tmp_carry = intrinsics.overflow_add(x, y) + sum, tmp_carry = intrinsics.overflow_add(x, y) sum, tmp_carry2 = intrinsics.overflow_add(sum, carry) carry_out = u64(tmp_carry | tmp_carry2) return } + +/* +Add with carry + +Inputs: +- x: The unsigned integer +- y: Another unsigned integer +- carry: Carry in + +Returns: +- sum: The sum +- carry_out: Carry out +*/ @(require_results) add_uint :: proc "contextless" (x, y, carry: uint) -> (sum, carry_out: uint) { when size_of(uint) == size_of(u64) { @@ -363,17 +610,54 @@ add_uint :: proc "contextless" (x, y, carry: uint) -> (sum, carry_out: uint) { } return uint(a), uint(b) } + +/* +Add with carry + +Inputs: +- x: The unsigned integer +- y: Another unsigned integer +- carry: Carry in + +Returns: +- sum: The sum +- carry_out: Carry out +*/ add :: proc{add_u32, add_u64, add_uint} +/* +Subtract with borrow +Inputs: +- x: The unsigned integer +- y: Another unsigned integer +- borrow: Borrow in + +Returns: +- diff: The difference +- borrow_out: Borrow out +*/ @(require_results) sub_u32 :: proc "contextless" (x, y, borrow: u32) -> (diff, borrow_out: u32) { tmp_borrow, tmp_borrow2: bool - diff, tmp_borrow = intrinsics.overflow_sub(x, y) + diff, tmp_borrow = intrinsics.overflow_sub(x, y) diff, tmp_borrow2 = intrinsics.overflow_sub(diff, borrow) borrow_out = u32(tmp_borrow | tmp_borrow2) return } + +/* +Subtract with borrow + +Inputs: +- x: The unsigned integer +- y: Another unsigned integer +- borrow: Borrow in + +Returns: +- diff: The difference +- borrow_out: Borrow out +*/ @(require_results) sub_u64 :: proc "contextless" (x, y, borrow: u64) -> (diff, borrow_out: u64) { tmp_borrow, tmp_borrow2: bool @@ -382,6 +666,19 @@ sub_u64 :: proc "contextless" (x, y, borrow: u64) -> (diff, borrow_out: u64) { borrow_out = u64(tmp_borrow | tmp_borrow2) return } + +/* +Subtract with borrow + +Inputs: +- x: The unsigned integer +- y: Another unsigned integer +- borrow: Borrow in + +Returns: +- diff: The difference +- borrow_out: Borrow out +*/ @(require_results) sub_uint :: proc "contextless" (x, y, borrow: uint) -> (diff, borrow_out: uint) { when size_of(uint) == size_of(u64) { @@ -392,15 +689,50 @@ sub_uint :: proc "contextless" (x, y, borrow: uint) -> (diff, borrow_out: uint) } return uint(a), uint(b) } + +/* +Subtract with borrow + +Inputs: +- x: The unsigned integer +- y: Another unsigned integer +- borrow: Borrow in + +Returns: +- diff: The difference +- borrow_out: Borrow out +*/ sub :: proc{sub_u32, sub_u64, sub_uint} +/* +Multiply two words and return the result in high and low word +Inputs: +- x: The unsigned integer +- y: Another unsigned integer + +Returns: +- hi: The result's high word +- lo: The result's low word +*/ @(require_results) mul_u32 :: proc "contextless" (x, y: u32) -> (hi, lo: u32) { z := u64(x) * u64(y) hi, lo = u32(z>>32), u32(z) return } + +/* +Multiply two words and return the result in high and low word + +Inputs: +- x: The unsigned integer +- y: Another unsigned integer + +Returns: +- hi: The result's high word +- lo: The result's low word +*/ @(require_results) mul_u64 :: proc "contextless" (x, y: u64) -> (hi, lo: u64) { prod_wide := u128(x) * u128(y) @@ -408,6 +740,17 @@ mul_u64 :: proc "contextless" (x, y: u64) -> (hi, lo: u64) { return } +/* +Multiply two words and return the result in high and low word + +Inputs: +- x: The unsigned integer +- y: Another unsigned integer + +Returns: +- hi: The result's high word +- lo: The result's low word +*/ @(require_results) mul_uint :: proc "contextless" (x, y: uint) -> (hi, lo: uint) { when size_of(uint) == size_of(u32) { @@ -419,9 +762,31 @@ mul_uint :: proc "contextless" (x, y: uint) -> (hi, lo: uint) { return uint(a), uint(b) } +/* +Multiply two words and return the result in high and low word + +Inputs: +- x: The unsigned integer +- y: Another unsigned integer + +Returns: +- hi: The result's high word +- lo: The result's low word +*/ mul :: proc{mul_u32, mul_u64, mul_uint} +/* +Divide a 64-bit unsigned integer (in two 32-bit words) by a 32-bit divisor +Inputs: +- hi: High word of 64-bit integer +- lo: Low word of 64-bit integer +- y: Divisor + +Returns: +- quo: 32-bit quotient +- rem: 32-bit remainder +*/ @(require_results) div_u32 :: proc "odin" (hi, lo, y: u32) -> (quo, rem: u32) { assert(y != 0 && y <= hi) @@ -429,6 +794,19 @@ div_u32 :: proc "odin" (hi, lo, y: u32) -> (quo, rem: u32) { quo, rem = u32(z/u64(y)), u32(z%u64(y)) return } + +/* +Divide a 128-bit unsigned integer (in two 64-bit words) by a 64-bit divisor + +Inputs: +- hi: High word of 128-bit integer +- lo: Low word of 128-bit integer +- y: Divisor + +Returns: +- quo: 64-bit quotient +- rem: 64-bit Remainder +*/ @(require_results) div_u64 :: proc "odin" (hi, lo, y: u64) -> (quo, rem: u64) { y := y @@ -475,6 +853,19 @@ div_u64 :: proc "odin" (hi, lo, y: u64) -> (quo, rem: u64) { return q1*two32 + q0, (un21*two32 + un0 - q0*y) >> s } + +/* +Divide an unsigned integer (in two words) by a divisor + +Inputs: +- hi: High word of input +- lo: Low word of input +- y: Divisor + +Returns: +- quo: Quotient +- rem: Remainder +*/ @(require_results) div_uint :: proc "odin" (hi, lo, y: uint) -> (quo, rem: uint) { when size_of(uint) == size_of(u32) { @@ -485,31 +876,150 @@ div_uint :: proc "odin" (hi, lo, y: uint) -> (quo, rem: uint) { } return uint(a), uint(b) } + +/* +Divide an unsigned integer (in two words) by a divisor + +Inputs: +- hi: High word of input +- lo: Low word of input +- y: Divisor + +Returns: +- quo: Quotient +- rem: Remainder +*/ div :: proc{div_u32, div_u64, div_uint} +/* +Checks whether an unsigned number is a power of two +Inputs: +- i: Unsigned number +Returns: +- is_pot: `true` if `i` is a power of two, `false` otherwise +*/ @(require_results) -is_power_of_two_u8 :: proc "contextless" (i: u8) -> bool { return i > 0 && (i & (i-1)) == 0 } -@(require_results) -is_power_of_two_i8 :: proc "contextless" (i: i8) -> bool { return i > 0 && (i & (i-1)) == 0 } -@(require_results) -is_power_of_two_u16 :: proc "contextless" (i: u16) -> bool { return i > 0 && (i & (i-1)) == 0 } -@(require_results) -is_power_of_two_i16 :: proc "contextless" (i: i16) -> bool { return i > 0 && (i & (i-1)) == 0 } -@(require_results) -is_power_of_two_u32 :: proc "contextless" (i: u32) -> bool { return i > 0 && (i & (i-1)) == 0 } -@(require_results) -is_power_of_two_i32 :: proc "contextless" (i: i32) -> bool { return i > 0 && (i & (i-1)) == 0 } -@(require_results) -is_power_of_two_u64 :: proc "contextless" (i: u64) -> bool { return i > 0 && (i & (i-1)) == 0 } -@(require_results) -is_power_of_two_i64 :: proc "contextless" (i: i64) -> bool { return i > 0 && (i & (i-1)) == 0 } -@(require_results) -is_power_of_two_uint :: proc "contextless" (i: uint) -> bool { return i > 0 && (i & (i-1)) == 0 } -@(require_results) -is_power_of_two_int :: proc "contextless" (i: int) -> bool { return i > 0 && (i & (i-1)) == 0 } +is_power_of_two_u8 :: proc "contextless" (i: u8) -> (is_pot: bool) { return i > 0 && (i & (i-1)) == 0 } +/* +Checks whether an unsigned number is a power of two + +Inputs: +- i: Unsigned number + +Returns: +- is_pot: `true` if `i` is a power of two, `false` otherwise +*/ +@(require_results) +is_power_of_two_i8 :: proc "contextless" (i: i8) -> (is_pot: bool) { return i > 0 && (i & (i-1)) == 0 } + +/* +Checks whether an unsigned number is a power of two + +Inputs: +- i: Unsigned number + +Returns: +- is_pot: `true` if `i` is a power of two, `false` otherwise +*/ +@(require_results) +is_power_of_two_u16 :: proc "contextless" (i: u16) -> (is_pot: bool) { return i > 0 && (i & (i-1)) == 0 } + +/* +Checks whether an unsigned number is a power of two + +Inputs: +- i: Unsigned number + +Returns: +- is_pot: `true` if `i` is a power of two, `false` otherwise +*/ +@(require_results) +is_power_of_two_i16 :: proc "contextless" (i: i16) -> (is_pot: bool) { return i > 0 && (i & (i-1)) == 0 } + +/* +Checks whether an unsigned number is a power of two + +Inputs: +- i: Unsigned number + +Returns: +- is_pot: `true` if `i` is a power of two, `false` otherwise +*/ +@(require_results) +is_power_of_two_u32 :: proc "contextless" (i: u32) -> (is_pot: bool) { return i > 0 && (i & (i-1)) == 0 } + +/* +Checks whether an unsigned number is a power of two + +Inputs: +- i: Unsigned number + +Returns: +- is_pot: `true` if `i` is a power of two, `false` otherwise +*/ +@(require_results) +is_power_of_two_i32 :: proc "contextless" (i: i32) -> (is_pot: bool) { return i > 0 && (i & (i-1)) == 0 } + +/* +Checks whether an unsigned number is a power of two + +Inputs: +- i: Unsigned number + +Returns: +- is_pot: `true` if `i` is a power of two, `false` otherwise +*/ +@(require_results) +is_power_of_two_u64 :: proc "contextless" (i: u64) -> (is_pot: bool) { return i > 0 && (i & (i-1)) == 0 } + +/* +Checks whether an unsigned number is a power of two + +Inputs: +- i: Unsigned number + +Returns: +- is_pot: `true` if `i` is a power of two, `false` otherwise +*/ +@(require_results) +is_power_of_two_i64 :: proc "contextless" (i: i64) -> (is_pot: bool) { return i > 0 && (i & (i-1)) == 0 } + +/* +Checks whether an unsigned number is a power of two + +Inputs: +- i: Unsigned number + +Returns: +- is_pot: `true` if `i` is a power of two, `false` otherwise +*/ +@(require_results) +is_power_of_two_uint :: proc "contextless" (i: uint) -> (is_pot: bool) { return i > 0 && (i & (i-1)) == 0 } + +/* +Checks whether an unsigned number is a power of two + +Inputs: +- i: Unsigned number + +Returns: +- is_pot: `true` if `i` is a power of two, `false` otherwise +*/ +@(require_results) +is_power_of_two_int :: proc "contextless" (i: int) -> (is_pot: bool) { return i > 0 && (i & (i-1)) == 0 } + +/* +Checks whether an unsigned number is a power of two + +Inputs: +- i: Unsigned number + +Returns: +- is_pot: `true` if `i` is a power of two, `false` otherwise +*/ is_power_of_two :: proc{ is_power_of_two_u8, is_power_of_two_i8, is_power_of_two_u16, is_power_of_two_i16, @@ -532,20 +1042,101 @@ len_u8_table := [256]u8{ 128..<256 = 8, } +/* +Extracts bits from an unsigned integer -@(require_results) -bitfield_extract_u8 :: proc "contextless" (value: u8, offset, bits: uint) -> u8 { return (value >> offset) & u8(1< u16 { return (value >> offset) & u16(1< u32 { return (value >> offset) & u32(1< u64 { return (value >> offset) & u64(1< u128 { return (value >> offset) & u128(1< uint { return (value >> offset) & uint(1< (res: u8) { return (value >> offset) & u8(1< (res: u16) { return (value >> offset) & u16(1< (res: u32) { return (value >> offset) & u32(1< (res: u64) { return (value >> offset) & u64(1< (res: u128) { return (value >> offset) & u128(1< (res: uint) { return (value >> offset) & uint(1< i8 { v := (u8(value) >> offset) & u8(1< i8 r := (v~m) - m return i8(r) } + +/* +Extracts bits from a signed integer + +Inputs: +- value: Signed integer +- offset: Offset (counting from LSB) at which to extract +- bits: Number of bits to extract + +Returns: +- res: `bits` bits starting at offset `offset` +*/ @(require_results) bitfield_extract_i16 :: proc "contextless" (value: i16, offset, bits: uint) -> i16 { v := (u16(value) >> offset) & u16(1< i r := (v~m) - m return i16(r) } + +/* +Extracts bits from a signed integer + +Inputs: +- value: Signed integer +- offset: Offset (counting from LSB) at which to extract +- bits: Number of bits to extract + +Returns: +- res: `bits` bits starting at offset `offset` +*/ @(require_results) bitfield_extract_i32 :: proc "contextless" (value: i32, offset, bits: uint) -> i32 { v := (u32(value) >> offset) & u32(1< i r := (v~m) - m return i32(r) } + +/* +Extracts bits from a signed integer + +Inputs: +- value: Signed integer +- offset: Offset (counting from LSB) at which to extract +- bits: Number of bits to extract + +Returns: +- res: `bits` bits starting at offset `offset` +*/ @(require_results) bitfield_extract_i64 :: proc "contextless" (value: i64, offset, bits: uint) -> i64 { v := (u64(value) >> offset) & u64(1< i r := (v~m) - m return i64(r) } + +/* +Extracts bits from a signed integer + +Inputs: +- value: Signed integer +- offset: Offset (counting from LSB) at which to extract +- bits: Number of bits to extract + +Returns: +- res: `bits` bits starting at offset `offset` +*/ @(require_results) bitfield_extract_i128 :: proc "contextless" (value: i128, offset, bits: uint) -> i128 { v := (u128(value) >> offset) & u128(1< r := (v~m) - m return i128(r) } + +/* +Extracts bits from a signed integer + +Inputs: +- value: Signed integer +- offset: Offset (counting from LSB) at which to extract +- bits: Number of bits to extract + +Returns: +- res: `bits` bits starting at offset `offset` +*/ @(require_results) bitfield_extract_int :: proc "contextless" (value: int, offset, bits: uint) -> int { v := (uint(value) >> offset) & uint(1< i return int(r) } +/* +Extracts bits from an integer +Inputs: +- value: Integer +- offset: Offset (counting from LSB) at which to extract +- bits: Number of bits to extract + +Returns: +- res: `bits` bits starting at offset `offset` +*/ bitfield_extract :: proc{ bitfield_extract_u8, bitfield_extract_u16, @@ -605,69 +1266,260 @@ bitfield_extract :: proc{ bitfield_extract_int, } +/* +Insert a subset of bits from one integer into another integer +Copies `bits` number of `insert`'s lower bits to `base` at `offset`. + +Inputs: +- base: Original integer to insert bits into +- insert: Integer to copy bits from +- offset: Bit offset in `base` at which to place `insert`'s bits +- bits: Number of bits to copy + +Returns: +- res: `base` with `bits` bits at `offset` replaced with `insert`'s +*/ @(require_results) -bitfield_insert_u8 :: proc "contextless" (base, insert: u8, offset, bits: uint) -> u8 { +bitfield_insert_u8 :: proc "contextless" (base, insert: u8, offset, bits: uint) -> (res: u8) { mask := u8(1< u16 { +bitfield_insert_u16 :: proc "contextless" (base, insert: u16, offset, bits: uint) -> (res: u16) { mask := u16(1< u32 { +bitfield_insert_u32 :: proc "contextless" (base, insert: u32, offset, bits: uint) -> (res: u32) { mask := u32(1< u64 { +bitfield_insert_u64 :: proc "contextless" (base, insert: u64, offset, bits: uint) -> (res: u64) { mask := u64(1< u128 { +bitfield_insert_u128 :: proc "contextless" (base, insert: u128, offset, bits: uint) -> (res: u128) { mask := u128(1< uint { +bitfield_insert_uint :: proc "contextless" (base, insert: uint, offset, bits: uint) -> (res: uint) { mask := uint(1< i8 { +bitfield_insert_i8 :: proc "contextless" (base, insert: i8, offset, bits: uint) -> (res: i8) { mask := i8(1< i16 { +bitfield_insert_i16 :: proc "contextless" (base, insert: i16, offset, bits: uint) -> (res: i16) { mask := i16(1< i32 { +bitfield_insert_i32 :: proc "contextless" (base, insert: i32, offset, bits: uint) -> (res: i32) { mask := i32(1< i64 { +bitfield_insert_i64 :: proc "contextless" (base, insert: i64, offset, bits: uint) -> (res: i64) { mask := i64(1< i128 { +bitfield_insert_i128 :: proc "contextless" (base, insert: i128, offset, bits: uint) -> (res: i128) { mask := i128(1< int { +bitfield_insert_int :: proc "contextless" (base, insert: int, offset, bits: uint) -> (res: int) { mask := int(1<