From 66735082b96033bed4f7e196e61feca0f2eee724 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 20 Oct 2026 04:11:02 +0700 Subject: [PATCH] t27o golden port 1: bootstrap/src/host/bitmask.rs becomes specs/host/bitmask.t27 and the Rust t27c gen-rust writes from it (Closes #11156) First golden port of step 4 of #9000. The 170-line hand file (96 lines of #[cfg(test)]) is deleted; its spec, converted by tri t27o and reviewed, is specs/host/bitmask.t27 (26 tests: the 14 of the hand file, one negative control, 11 oracle tests recorded from the hand file), sealed in .trinity/seals/host_HostBitmask.json. t27c gen-rust writes bootstrap/gen/rust/host/bitmask.rs, which host/mod.rs mounts by #[path] as module bitmask; the pub use line of mod.rs is unchanged, so no caller changes. Hand lines: +1 / -171 (the mount line replaces the pub mod line). Co-Authored-By: Claude Sonnet 5.5 --- .trinity/seals/host_HostBitmask.json | 37 +++ bootstrap/gen/rust/host/bitmask.rs | 159 ++++++++++++ bootstrap/src/host/bitmask.rs | 170 ------------- bootstrap/src/host/mod.rs | 2 +- specs/host/bitmask.t27 | 351 +++++++++++++++++++++++++++ 5 files changed, 548 insertions(+), 171 deletions(-) create mode 100644 .trinity/seals/host_HostBitmask.json create mode 100644 bootstrap/gen/rust/host/bitmask.rs delete mode 100644 bootstrap/src/host/bitmask.rs create mode 100644 specs/host/bitmask.t27 diff --git a/.trinity/seals/host_HostBitmask.json b/.trinity/seals/host_HostBitmask.json new file mode 100644 index 0000000000..35b1529f5e --- /dev/null +++ b/.trinity/seals/host_HostBitmask.json @@ -0,0 +1,37 @@ +{ + "built_by": "t27c-bootstrap@0.5.2+16c7dcf13", + "closure": [ + { + "spec": "specs/tools/t27o/rust_std.t27", + "spec_hash": "sha256:e72606b4b3d7611883db25ed9fdaecb4353fe6a1fef551500b3cd1cc18cceb79" + }, + { + "spec": "specs/tri/t27b/type_text.t27", + "spec_hash": "sha256:0c2ea71bc30d0865c2fb2206de7a0499e836bba7da6d1340bb1bef116823f473" + } + ], + "config": "gen=c,rust,verilog,zig;tests=zig", + "gen_hash_c": "sha256:4b92d691af8c75a08f74f4fd8190e8e133cf48c9278773285857f0ea9e7cf649", + "gen_hash_rust": "sha256:d23e868976b1ffaf31580506330bcb7bcd2f8424dabe03e3feb7f30d1ce6e615", + "gen_hash_verilog": "sha256:df64508ffd13a8134313fdd670c295f77734e5d4f9b73d9ac73105aed813b25a", + "gen_hash_zig": "sha256:c3694cee445fb9a42a0b5664e84301e9c375268835d77ac31147acbfa6df43c0", + "module": "HostBitmask", + "ring": 12, + "seal_schema": 2, + "sealed_at": "2026-10-19T21:07:46Z", + "sealed_by": "t27c-bootstrap@0.5.2", + "spec_hash": "sha256:df6cf1c8763172ff834e92b531c8eba063fa5ac0dd5ed6b63e497e604e35880b", + "spec_path": "specs/host/bitmask.t27", + "tests": { + "failed": 0, + "failing": [], + "forced": false, + "passed": 26, + "total": 26, + "vacuous": 0 + }, + "toolchain": { + "test_runner": "sha256:8512b80da533b79289110fca4a65f3336abd7a059ca4b72ea595d5e33ff8ad10", + "zig": "0.16.0" + } +} \ No newline at end of file diff --git a/bootstrap/gen/rust/host/bitmask.rs b/bootstrap/gen/rust/host/bitmask.rs new file mode 100644 index 0000000000..9406ec82a9 --- /dev/null +++ b/bootstrap/gen/rust/host/bitmask.rs @@ -0,0 +1,159 @@ +// Generated from .t27 spec +// DO NOT EDIT — generated by t27c +// NOT LOWERED BY THIS BACKEND: 26 test(s), 0 invariant(s), 0 function(s) with no body. +// This backend emits declarations only. The spec's checks live in +// the Zig and Verilog outputs; do not read this file as verified. + +pub fn mask(width: u8) -> u32 { + if (width >= 32) { + return 0xFFFFFFFF; + } else { + return (((1 as u32) << width) - 1); + } +} + +pub fn field_mask(high: u8, low: u8) -> u32 { + return (mask(((high - low) + 1)) << low); +} + +pub fn extract(value: u32, high: u8, low: u8) -> u32 { + return ((value >> low) & mask(((high - low) + 1))); +} + +pub fn insert(value: u32, high: u8, low: u8, field: u32) -> u32 { + let m = field_mask(high, low); + return ((value & !(m)) | ((field << low) & m)); +} + +pub fn is_set(value: u32, bit: u8) -> bool { + return ((value & ((1 as u32) << bit)) != 0); +} + +pub fn set_bit(value: u32, bit: u8) -> u32 { + return (value | ((1 as u32) << bit)); +} + +pub fn clear_bit(value: u32, bit: u8) -> u32 { + return (value & !(((1 as u32) << bit))); +} + +pub fn toggle_bit(value: u32, bit: u8) -> u32 { + return (value ^ ((1 as u32) << bit)); +} + +pub fn popcount(value: u32) -> u8 { + return (count_ones_u32(value) as u8); +} + +pub fn trailing_zeros(value: u32) -> u8 { + return (trailing_zeros_u32(value) as u8); +} + +pub fn leading_zeros(value: u32) -> u8 { + return (leading_zeros_u32(value) as u8); +} + +#[derive(Debug, Clone, Copy)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct FieldDesc { + pub name: &'static str, + pub high: u8, + pub low: u8, +} + +pub fn FieldDesc_new(name: &'static str, high: u8, low: u8) -> FieldDesc { + return FieldDesc { name: name, high: high, low: low }; +} + +pub fn FieldDesc_width(self_: FieldDesc) -> u8 { + return ((self_.high - self_.low) + 1); +} + +pub fn FieldDesc_mask(self_: FieldDesc) -> u32 { + return field_mask(self_.high, self_.low); +} + +pub fn FieldDesc_extract(self_: FieldDesc, value: u32) -> u32 { + return extract(value, self_.high, self_.low); +} + +pub fn FieldDesc_insert(self_: FieldDesc, value: u32, field: u32) -> u32 { + return insert(value, self_.high, self_.low, field); +} + +pub fn count_ones_u32(x: u32) -> u32 { + return count_ones_u64((x as u64)); +} + +pub fn count_ones_u64(x: u64) -> u32 { + let mut c: u32 = 0; + let mut y: u64 = x; + while (y != 0) { + c = (c + ((y & 1) as u32)); + y = (y >> 1); + } + return c; +} + +pub fn leading_zeros_u32(x: u32) -> u32 { + return (leading_zeros_u64((x as u64)) - 32); +} + +pub fn leading_zeros_u64(x: u64) -> u32 { + let mut c: u32 = 0; + let mut y: u64 = x; + while ((c < 64) && ((y & 9223372036854775808) == 0)) { + y = (y << 1); + c = (c + 1); + } + return c; +} + +pub fn trailing_zeros_u32(x: u32) -> u32 { + if (x == 0) { + return 32; + } + return trailing_zeros_u64((x as u64)); +} + +pub fn trailing_zeros_u64(x: u64) -> u32 { + if (x == 0) { + return 64; + } + let mut c: u32 = 0; + let mut y: u64 = x; + while ((y & 1) == 0) { + y = (y >> 1); + c = (c + 1); + } + return c; +} + +pub const B_UNDERSCORE: u8 = 95; + +pub fn alpha(c: u8) -> bool { + return (((c >= 65) && (c <= 90)) || ((c >= 97) && (c <= 122))); +} + +pub fn digit(c: u8) -> bool { + return ((c >= 48) && (c <= 57)); +} + +pub fn same(s: &[u8], w: &'static str) -> bool { + if (s.len() != w.len()) { + return false; + } + let mut k: usize = 0; + while (k < w.len()) { + if (s[(k) as usize] != w.as_bytes()[(k) as usize]) { + return false; + } + k = (k + 1); + } + return true; +} + +pub fn word(c: u8) -> bool { + return ((alpha(c) || digit(c)) || (c == B_UNDERSCORE)); +} + diff --git a/bootstrap/src/host/bitmask.rs b/bootstrap/src/host/bitmask.rs deleted file mode 100644 index 48d705956a..0000000000 --- a/bootstrap/src/host/bitmask.rs +++ /dev/null @@ -1,170 +0,0 @@ -pub const fn mask(width: u8) -> u32 { - if width >= 32 { 0xFFFF_FFFF } else { (1u32 << width) - 1 } -} - -pub const fn field_mask(high: u8, low: u8) -> u32 { - mask(high - low + 1) << low -} - -pub const fn extract(value: u32, high: u8, low: u8) -> u32 { - (value >> low) & mask(high - low + 1) -} - -pub const fn insert(value: u32, high: u8, low: u8, field: u32) -> u32 { - let m = field_mask(high, low); - (value & !m) | ((field << low) & m) -} - -pub const fn is_set(value: u32, bit: u8) -> bool { - (value & (1u32 << bit)) != 0 -} - -pub const fn set_bit(value: u32, bit: u8) -> u32 { - value | (1u32 << bit) -} - -pub const fn clear_bit(value: u32, bit: u8) -> u32 { - value & !(1u32 << bit) -} - -pub const fn toggle_bit(value: u32, bit: u8) -> u32 { - value ^ (1u32 << bit) -} - -pub fn popcount(value: u32) -> u8 { - value.count_ones() as u8 -} - -pub fn trailing_zeros(value: u32) -> u8 { - value.trailing_zeros() as u8 -} - -pub fn leading_zeros(value: u32) -> u8 { - value.leading_zeros() as u8 -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct FieldDesc { - pub name: &'static str, - pub high: u8, - pub low: u8, -} - -impl FieldDesc { - pub const fn new(name: &'static str, high: u8, low: u8) -> Self { - Self { name, high, low } - } - - pub const fn width(self) -> u8 { - self.high - self.low + 1 - } - - pub const fn mask(self) -> u32 { - field_mask(self.high, self.low) - } - - pub const fn extract(self, value: u32) -> u32 { - extract(value, self.high, self.low) - } - - pub const fn insert(self, value: u32, field: u32) -> u32 { - insert(value, self.high, self.low, field) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn mask_1bit() { - assert_eq!(mask(1), 0x1); - } - - #[test] - fn mask_8bit() { - assert_eq!(mask(8), 0xFF); - } - - #[test] - fn mask_32bit() { - assert_eq!(mask(32), 0xFFFF_FFFF); - } - - #[test] - fn field_mask_bits_7_4() { - assert_eq!(field_mask(7, 4), 0xF0); - } - - #[test] - fn extract_field() { - let v = 0xABCD; - assert_eq!(extract(v, 11, 8), 0xB); - assert_eq!(extract(v, 3, 0), 0xD); - } - - #[test] - fn insert_field() { - let v = 0x0000; - assert_eq!(insert(v, 7, 4, 0xA), 0x00A0); - } - - #[test] - fn insert_preserves_other() { - let v = 0x1234; - let result = insert(v, 7, 4, 0x0); - assert_eq!(extract(result, 15, 8), 0x12); - assert_eq!(extract(result, 3, 0), 0x4); - } - - #[test] - fn is_set_clear() { - assert!(is_set(0x04, 2)); - assert!(!is_set(0x04, 1)); - } - - #[test] - fn set_clear_toggle() { - assert_eq!(set_bit(0, 3), 0x08); - assert_eq!(clear_bit(0xFF, 0), 0xFE); - assert_eq!(toggle_bit(0x0F, 3), 0x07); - assert_eq!(toggle_bit(0x07, 3), 0x0F); - } - - #[test] - fn popcount_test() { - assert_eq!(popcount(0xFF), 8); - assert_eq!(popcount(0), 0); - assert_eq!(popcount(1), 1); - } - - #[test] - fn trailing_zeros_test() { - assert_eq!(trailing_zeros(0x08), 3); - assert_eq!(trailing_zeros(1), 0); - } - - #[test] - fn field_desc() { - let f = FieldDesc::new("ctrl_start", 0, 0); - assert_eq!(f.width(), 1); - assert_eq!(f.mask(), 0x1); - assert_eq!(f.extract(0x01), 1); - assert_eq!(f.insert(0, 1), 1); - } - - #[test] - fn field_desc_wide() { - let f = FieldDesc::new("neurons", 15, 0); - assert_eq!(f.width(), 16); - assert_eq!(f.mask(), 0xFFFF); - assert_eq!(f.extract(0x00FF_0000), 0); - assert_eq!(f.extract(0x0000_ABCD), 0xABCD); - } - - #[test] - fn insert_overwrite() { - let v = insert(0x00F0, 7, 4, 0x5); - assert_eq!(v, 0x0050); - } -} diff --git a/bootstrap/src/host/mod.rs b/bootstrap/src/host/mod.rs index 2cc60686e3..cfdc3839c0 100644 --- a/bootstrap/src/host/mod.rs +++ b/bootstrap/src/host/mod.rs @@ -23,7 +23,7 @@ #![cfg_attr(not(test), allow(unused_imports))] pub mod addrmap; -pub mod bitmask; +#[path = "../../gen/rust/host/bitmask.rs"] #[allow(dead_code, unused_parens, unused_mut, unused_variables, non_snake_case, unused_assignments, unexpected_cfgs, clippy::all)] pub mod bitmask; // specs/host/bitmask.t27, by `t27c gen-rust` pub mod bitstream; pub mod bufchain; pub mod capflags; diff --git a/specs/host/bitmask.t27 b/specs/host/bitmask.t27 new file mode 100644 index 0000000000..eeced2ab3a --- /dev/null +++ b/specs/host/bitmask.t27 @@ -0,0 +1,351 @@ +// SPDX-License-Identifier: Apache-2.0 +; specs/host/bitmask.t27 -- bit-field arithmetic of the host driver for the BitNet AXI-Lite CSR aperture: +; the mask of a field, reading and writing a field of a 32-bit register word, single-bit tests and edits, +; and the width and mask of a named field (Closes #11156, the first golden port of step 4 of #9000). +; -- +; This spec replaces the hand-written bootstrap/src/host/bitmask.rs (170 lines, 96 of them #[cfg(test)]). +; The file was converted by `tri t27o` (rules: specs/tools/t27o/rust_convert.t27), read by eye, and its 14 +; Rust #[test]s are the 14 `test` blocks below that carry their names. `t27c gen-rust` lowers this spec to +; bootstrap/gen/rust/host/bitmask.rs, which bootstrap/src/host/mod.rs mounts by #[path] as module `bitmask`; +; the `pub use bitmask::{..}` line of mod.rs is unchanged, so no caller changes. Never hand-edit the +; generated copy. +; -- +; Rules, each pinned by a test below: +; R1 (masks). mask(w) is the low w bits set, and all 32 for w >= 32; field_mask(high, low) is the bits low +; to high inclusive, so the width of a field is high - low + 1. +; R2 (a field of a word). extract(v, high, low) is that field moved to bit 0; insert(v, high, low, f) is v +; with that field replaced by f, where the bits of f above the field are dropped and every bit outside +; the field keeps its value. +; R3 (single bits). is_set, set_bit, clear_bit and toggle_bit take a bit number below 32. +; R4 (counts). popcount, trailing_zeros and leading_zeros count over 32 bits, so the last two are 32 for 0. +; R5 (no checks). Like the file it replaces, nothing here refuses an argument: high below low, or a bit +; number of 32 or more, is an overflow of the Rust the spec lowers to (a panic in a debug build). +; -- +; What the lowering changes, stated here so that nobody reads it as a surprise: gen-rust writes `pub fn` +; where the hand file wrote `pub const fn`, and a method of FieldDesc becomes a free fn named +; FieldDesc_ whose first parameter is `self_`; the struct derives Debug, Clone and Copy and no +; longer PartialEq and Eq. No file of the repository uses a const context, a method or an equality of +; these items; mod.rs re-exports ten names (nine fns and FieldDesc), all of which keep their names and +; types. +; -- +; The test named `negative_control_..` plants the fault of an insert that does not cut its field. The +; `oracle_*` tests at the end are the values the hand file returned when `tri t27o --check` compiled it +; with rustc and ran it; they are kept so that the behaviour of the deleted file stays on record. +; ASCII only (L3) +; phi^2 + 1/phi^2 = 3 | TRINITY + +module HostBitmask; + +use tools::t27o::rust_std; +use tri::t27b::type_text; + +/// The low `width` bits set; all 32 bits when `width` is 32 or more. +pub fn mask(width: u8) -> u32 { + if (width >= 32) { + return 0xFFFFFFFF; + } else { + return (@as(u32, 1) << width) - 1; + } +} + +/// The bits `low` to `high` inclusive, in place. `high` is not below `low`. +pub fn field_mask(high: u8, low: u8) -> u32 { + return mask(high - low + 1) << low; +} + +/// The field `high` to `low` of `value`, moved to bit 0. +pub fn extract(value: u32, high: u8, low: u8) -> u32 { + return (value >> low) & mask(high - low + 1); +} + +/// `value` with its field `high` to `low` replaced by `field`; the bits of `field` above the field are +/// dropped and the bits of `value` outside the field are kept. +pub fn insert(value: u32, high: u8, low: u8, field: u32) -> u32 { + const m = field_mask(high, low); + return (value & ~m) | ((field << low) & m); +} + +/// Whether bit number `bit` (below 32) of `value` is 1. +pub fn is_set(value: u32, bit: u8) -> bool { + return (value & (@as(u32, 1) << bit)) != 0; +} + +pub fn set_bit(value: u32, bit: u8) -> u32 { + return value | (@as(u32, 1) << bit); +} + +pub fn clear_bit(value: u32, bit: u8) -> u32 { + return value & ~(@as(u32, 1) << bit); +} + +pub fn toggle_bit(value: u32, bit: u8) -> u32 { + return value ^ (@as(u32, 1) << bit); +} + +/// The number of 1 bits of `value`, 0 to 32. +pub fn popcount(value: u32) -> u8 { + return rust_std::count_ones_u32(value) as u8; +} + +/// The number of 0 bits below the lowest 1 bit of `value`; 32 for 0. +pub fn trailing_zeros(value: u32) -> u8 { + return rust_std::trailing_zeros_u32(value) as u8; +} + +/// The number of 0 bits above the highest 1 bit of `value`; 32 for 0. +pub fn leading_zeros(value: u32) -> u8 { + return rust_std::leading_zeros_u32(value) as u8; +} + +/// A named field of a register word: bits `low` to `high` inclusive. +pub const FieldDesc = struct { + name : []const u8, + high : u8, + low : u8, +}; + +pub fn FieldDesc_new(name: []const u8, high: u8, low: u8) -> FieldDesc { + return FieldDesc{ .name = name, .high = high, .low = low }; +} + +/// The number of bits of the field. +pub fn FieldDesc_width(self: FieldDesc) -> u8 { + return self.high - self.low + 1; +} + +pub fn FieldDesc_mask(self: FieldDesc) -> u32 { + return field_mask(self.high, self.low); +} + +pub fn FieldDesc_extract(self: FieldDesc, value: u32) -> u32 { + return extract(value, self.high, self.low); +} + +pub fn FieldDesc_insert(self: FieldDesc, value: u32, field: u32) -> u32 { + return insert(value, self.high, self.low, field); +} + +; --- The 14 tests of the hand file, as `tri t27o` translated them. ---------------------------------- + +test mask_1bit { + assert(mask(1) == 0x1); +} + +test mask_8bit { + assert(mask(8) == 0xFF); +} + +test mask_32bit { + assert(mask(32) == 0xFFFFFFFF); +} + +test field_mask_bits_7_4 { + assert(field_mask(7, 4) == 0xF0); +} + +test extract_field { + const v = 0xABCD; + assert(extract(v, 11, 8) == 0xB); + assert(extract(v, 3, 0) == 0xD); +} + +test insert_field { + const v = 0x0000; + assert(insert(v, 7, 4, 0xA) == 0x00A0); +} + +test insert_preserves_other { + const v = 0x1234; + const result = insert(v, 7, 4, 0x0); + assert(extract(result, 15, 8) == 0x12); + assert(extract(result, 3, 0) == 0x4); +} + +test is_set_clear { + assert(is_set(0x04, 2)); + assert(!is_set(0x04, 1)); +} + +test set_clear_toggle { + assert(set_bit(0, 3) == 0x08); + assert(clear_bit(0xFF, 0) == 0xFE); + assert(toggle_bit(0x0F, 3) == 0x07); + assert(toggle_bit(0x07, 3) == 0x0F); +} + +test popcount_test { + assert(popcount(0xFF) == 8); + assert(popcount(0) == 0); + assert(popcount(1) == 1); +} + +test trailing_zeros_test { + assert(trailing_zeros(0x08) == 3); + assert(trailing_zeros(1) == 0); +} + +test field_desc { + const f = FieldDesc_new("ctrl_start", 0, 0); + assert(FieldDesc_width(f) == 1); + assert(FieldDesc_mask(f) == 0x1); + assert(FieldDesc_extract(f, 0x01) == 1); + assert(FieldDesc_insert(f, 0, 1) == 1); +} + +test field_desc_wide { + const f = FieldDesc_new("neurons", 15, 0); + assert(FieldDesc_width(f) == 16); + assert(FieldDesc_mask(f) == 0xFFFF); + assert(FieldDesc_extract(f, 0x00FF0000) == 0); + assert(FieldDesc_extract(f, 0x0000ABCD) == 0xABCD); +} + +test insert_overwrite { + const v = insert(0x00F0, 7, 4, 0x5); + assert(v == 0x0050); +} + +; --- A fault planted: an insert that forgot to cut the field would spill into its neighbour. -------- + +test negative_control_a_field_wider_than_its_slot_is_cut_and_the_neighbours_are_kept { + // the values are what the hand file returns (checked by running it) + assert(insert(0x1200, 7, 4, 0x1FF) == 0x12F0); + assert(insert(0xFFFFFFFF, 7, 4, 0) == 0xFFFFFF0F); + assert(extract(0xFFFFFFFF, 7, 4) == 0xF); + assert(insert(0, 31, 0, 0xFFFFFFFF) == 0xFFFFFFFF); + assert(field_mask(31, 0) == 0xFFFFFFFF); + assert(field_mask(31, 31) == 0x80000000); + assert(extract(0xDEADBEEF, 31, 28) == 0xD); + assert(insert(0xFFFFFFFF, 31, 28, 0) == 0x0FFFFFFF); +} + +; --- The values the hand file returned when it was compiled with rustc and run (`tri t27o --check`). --- +// t27o: 30 fn seen, 30 converted (14 of 14 tests), 0 refused (0 kept as stubs); coverage 100% + +test oracle_mask { + assert(mask(0) == 0); + assert(mask(1) == 1); + assert(mask(2) == 3); + assert(mask(7) == 127); + assert(mask(10) == 1023); + assert(mask(100) == 4294967295); + assert(mask(255) == 4294967295); + assert(mask(31) == 2147483647); + assert(mask(32) == 4294967295); + assert(mask(33) == 4294967295); + assert(mask(0) == 0); + assert(mask(1) == 1); + assert(mask(2) == 3); + assert(mask(0) == 0); +} + +test oracle_field_mask { + assert(field_mask(2, 0) == 7); +} + +test oracle_extract { + assert(extract(1, 2, 0) == 1); +} + +test oracle_is_set { + assert(is_set(0, 1) == false); + assert(is_set(1, 2) == false); + assert(is_set(2, 7) == false); + assert(is_set(7, 10) == false); + assert(is_set(4294967295, 0) == true); + assert(is_set(0, 1) == false); + assert(is_set(1, 2) == false); + assert(is_set(2, 0) == false); + assert(is_set(0, 1) == false); + assert(is_set(1, 0) == true); +} + +test oracle_set_bit { + assert(set_bit(0, 1) == 2); + assert(set_bit(1, 2) == 5); + assert(set_bit(2, 7) == 130); + assert(set_bit(7, 10) == 1031); + assert(set_bit(4294967295, 0) == 4294967295); + assert(set_bit(0, 1) == 2); + assert(set_bit(1, 2) == 5); + assert(set_bit(2, 0) == 3); +} + +test oracle_clear_bit { + assert(clear_bit(0, 1) == 0); + assert(clear_bit(1, 2) == 1); + assert(clear_bit(2, 7) == 2); + assert(clear_bit(7, 10) == 7); + assert(clear_bit(4294967295, 0) == 4294967294); + assert(clear_bit(0, 1) == 0); + assert(clear_bit(1, 2) == 1); + assert(clear_bit(2, 0) == 2); +} + +test oracle_toggle_bit { + assert(toggle_bit(0, 1) == 2); + assert(toggle_bit(1, 2) == 5); + assert(toggle_bit(2, 7) == 130); + assert(toggle_bit(7, 10) == 1031); + assert(toggle_bit(4294967295, 0) == 4294967294); + assert(toggle_bit(0, 1) == 2); + assert(toggle_bit(1, 2) == 5); + assert(toggle_bit(2, 0) == 3); +} + +test oracle_popcount { + assert(popcount(0) == 0); + assert(popcount(1) == 1); + assert(popcount(2) == 1); + assert(popcount(7) == 3); + assert(popcount(10) == 2); + assert(popcount(100) == 3); + assert(popcount(4294967295) == 32); +} + +test oracle_trailing_zeros { + assert(trailing_zeros(0) == 32); + assert(trailing_zeros(1) == 0); + assert(trailing_zeros(2) == 1); + assert(trailing_zeros(7) == 0); + assert(trailing_zeros(10) == 1); + assert(trailing_zeros(100) == 2); + assert(trailing_zeros(4294967295) == 0); +} + +test oracle_leading_zeros { + assert(leading_zeros(0) == 32); + assert(leading_zeros(1) == 31); + assert(leading_zeros(2) == 30); + assert(leading_zeros(7) == 29); + assert(leading_zeros(10) == 28); + assert(leading_zeros(100) == 25); + assert(leading_zeros(4294967295) == 0); +} + +test oracle_FieldDesc_new { + assert(type_text::same(FieldDesc_new("", 1, 2).name, "")); + assert(FieldDesc_new("", 1, 2).high == 1); + assert(FieldDesc_new("", 1, 2).low == 2); + assert(type_text::same(FieldDesc_new("a", 2, 7).name, "a")); + assert(FieldDesc_new("a", 2, 7).high == 2); + assert(FieldDesc_new("a", 2, 7).low == 7); + assert(type_text::same(FieldDesc_new("abc", 7, 10).name, "abc")); + assert(FieldDesc_new("abc", 7, 10).high == 7); + assert(FieldDesc_new("abc", 7, 10).low == 10); + assert(type_text::same(FieldDesc_new("0", 10, 100).name, "0")); + assert(FieldDesc_new("0", 10, 100).high == 10); + assert(FieldDesc_new("0", 10, 100).low == 100); + assert(type_text::same(FieldDesc_new("42", 100, 255).name, "42")); + assert(FieldDesc_new("42", 100, 255).high == 100); + assert(FieldDesc_new("42", 100, 255).low == 255); + assert(type_text::same(FieldDesc_new("0x1f", 255, 0).name, "0x1f")); + assert(FieldDesc_new("0x1f", 255, 0).high == 255); + assert(FieldDesc_new("0x1f", 255, 0).low == 0); + assert(type_text::same(FieldDesc_new("a b", 0, 1).name, "a b")); + assert(FieldDesc_new("a b", 0, 1).high == 0); + assert(FieldDesc_new("a b", 0, 1).low == 1); + assert(type_text::same(FieldDesc_new("-7", 1, 2).name, "-7")); + assert(FieldDesc_new("-7", 1, 2).high == 1); + assert(FieldDesc_new("-7", 1, 2).low == 2); +}