From 6a2984540b5cc0d70966b10b3e6e7c73d5c910a8 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 18 Jul 2024 15:48:52 +0200 Subject: [PATCH 1/2] bitpattern: comments --- kernel/bitpattern.h | 49 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/kernel/bitpattern.h b/kernel/bitpattern.h index 821490dca..0e12e6dce 100644 --- a/kernel/bitpattern.h +++ b/kernel/bitpattern.h @@ -25,6 +25,18 @@ YOSYS_NAMESPACE_BEGIN +/** + * This file implements BitPatternPool for efficiently storing and querying + * sets of fixed-width 2-valued logic constants compressed as "bit patterns". + * A bit pattern can have don't cares on one or more bit positions (State::Sa). + * + * In terms of logic synthesis: + * A BitPatternPool is a sum of products (SOP). + * BitPatternPool::bits_t is a cube. + * + * BitPatternPool does not permit adding new patterns, only removing. + * Its intended use case is in analysing cases in case/match constructs in HDL. + */ struct BitPatternPool { int width; @@ -67,6 +79,9 @@ struct BitPatternPool } } + /** + * Constructs a pool of all possible patterns (all don't-care bits) + */ BitPatternPool(int width) { this->width = width; @@ -78,6 +93,10 @@ struct BitPatternPool } } + /** + * Convert a constant SigSpec to a pattern. Normalize Yosys many-valued + * to three-valued logic. + */ bits_t sig2bits(RTLIL::SigSpec sig) { bits_t bits; @@ -88,6 +107,9 @@ struct BitPatternPool return bits; } + /** + * Two cubes match if their intersection is non-empty. + */ bool match(bits_t a, bits_t b) { log_assert(int(a.bitdata.size()) == width); @@ -98,6 +120,15 @@ struct BitPatternPool return true; } + /** + * Does cube sig overlap any cube in the pool? + * For example: + * pool({aaa}).has_any(01a) == true + * pool({01a}).has_any(01a) == true + * pool({011}).has_any(01a) == true + * pool({01a}).has_any(011) == true + * pool({111}).has_any(01a) == false + */ bool has_any(RTLIL::SigSpec sig) { bits_t bits = sig2bits(sig); @@ -107,6 +138,15 @@ struct BitPatternPool return false; } + /** + * Is cube sig covered by a cube in the pool? + * For example: + * pool({aaa}).has_all(01a) == true + * pool({01a}).has_any(01a) == true + * pool({01a}).has_any(011) == true + * pool({011}).has_all(01a) == false + * pool({111}).has_all(01a) == false + */ bool has_all(RTLIL::SigSpec sig) { bits_t bits = sig2bits(sig); @@ -121,6 +161,12 @@ struct BitPatternPool return false; } + /** + * Remove cube sig from the pool, splitting the remaining cubes. True if success. + * For example: + * Taking 011 out of pool({01a}) -> pool({010}), returns true. + * Taking 011 out of pool({010}) does nothing, returns false. + */ bool take(RTLIL::SigSpec sig) { bool status = false; @@ -143,6 +189,9 @@ struct BitPatternPool return status; } + /** + * Remove all patterns. Returns false if already empty. + */ bool take_all() { if (database.empty()) From 7ee62c832b19d5b18b822af7603a6fb1898ca748 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 18 Aug 2025 19:50:43 +0200 Subject: [PATCH 2/2] bitpattern: unit test --- tests/unit/kernel/bitpatternTest.cc | 32 +++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 tests/unit/kernel/bitpatternTest.cc diff --git a/tests/unit/kernel/bitpatternTest.cc b/tests/unit/kernel/bitpatternTest.cc new file mode 100644 index 000000000..001d47060 --- /dev/null +++ b/tests/unit/kernel/bitpatternTest.cc @@ -0,0 +1,32 @@ +#include + +#include "kernel/bitpattern.h" +#include "kernel/rtlil.h" + +YOSYS_NAMESPACE_BEGIN + +TEST(BitpatternTest, has) +{ + SigSpec _aaa = {RTLIL::Sa, RTLIL::Sa, RTLIL::Sa}; + SigSpec _01a = {RTLIL::S0, RTLIL::S1, RTLIL::Sa}; + SigSpec _011 = {RTLIL::S0, RTLIL::S1, RTLIL::S1}; + SigSpec _111 = {RTLIL::S1, RTLIL::S1, RTLIL::S1}; + + EXPECT_TRUE(BitPatternPool(_aaa).has_any(_01a)); + EXPECT_TRUE(BitPatternPool(_01a).has_any(_01a)); + // 011 overlaps with 01a + EXPECT_TRUE(BitPatternPool(_011).has_any(_01a)); + // overlap is symmetric + EXPECT_TRUE(BitPatternPool(_01a).has_any(_011)); + EXPECT_FALSE(BitPatternPool(_111).has_any(_01a)); + + EXPECT_TRUE(BitPatternPool(_aaa).has_all(_01a)); + EXPECT_TRUE(BitPatternPool(_01a).has_all(_01a)); + // 011 is covered by 01a + EXPECT_TRUE(BitPatternPool(_01a).has_all(_011)); + // 01a is not covered by 011 + EXPECT_FALSE(BitPatternPool(_011).has_all(_01a)); + EXPECT_FALSE(BitPatternPool(_111).has_all(_01a)); +} + +YOSYS_NAMESPACE_END